Conversation
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Introduce `Unnormalized` wrapper
This comment has been minimized.
This comment has been minimized.
|
@bors try cancel |
|
Try build cancelled. Cancelled workflows: |
309b0de to
a616210
Compare
This comment has been minimized.
This comment has been minimized.
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Introduce `Unnormalized` wrapper
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (10d0ef4): comparison URL. Overall result: no relevant changes - no action neededBenchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. @bors rollup=never Instruction countThis perf run didn't have relevant results for this metric. Max RSS (memory usage)Results (primary -2.4%, secondary -6.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary -0.7%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 492.281s -> 489.321s (-0.60%) |
3b64c2b to
5407a88
Compare
|
r? @lcnr |
This comment has been minimized.
This comment has been minimized.
53bb180 to
d9fa04c
Compare
| { | ||
| self.normalize_with_category(value, location, ConstraintCategory::Boring) | ||
| self.normalize_with_category( | ||
| Unnormalized::new_wip(value), |
There was a problem hiding this comment.
not propagating this one out?
| where | ||
| T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, | ||
| { | ||
| let value = value.inside_norm(); |
There was a problem hiding this comment.
| let value = value.inside_norm(); | |
| let value = value.skip_norm_wip(); |
would want us to propagate the Unnormalized into the type op and only discard it when actually normalizing
| let unnormalized_ty = | ||
| tcx.type_of(static_def_id).instantiate_identity().skip_norm_wip(); | ||
| let normalized_ty = self.normalize(unnormalized_ty, locations); |
There was a problem hiding this comment.
hmm, want to change TypeChecker::normalize to also take Unnormalized
| // restrictive than the trait's method (and the impl itself). | ||
| let impl_m_own_bounds = impl_m_predicates.instantiate_own_identity(); | ||
| let impl_m_own_bounds = | ||
| impl_m_predicates.instantiate_own_identity().map(|(c, s)| (c.skip_norm_wip(), s)); |
There was a problem hiding this comment.
that skip_norm_wip seems overeager given that we do actually just do ocx.normalize on that predicate right afer
| for (const_condition, span) in tcx | ||
| .const_conditions(impl_m.def_id) | ||
| .instantiate_own_identity() | ||
| .map(|(c, s)| (c.skip_norm_wip(), s)) |
There was a problem hiding this comment.
same here
| continue; | ||
| } | ||
| if !tcx.is_dyn_compatible(trait_ref.def_id) { | ||
| if !tcx.is_dyn_compatible(trait_ref.probe(|v| v.def_id)) { |
There was a problem hiding this comment.
probe is an overloaded name in the type system 🤔 maybe .extract
I would not use this to get a def_id as I want that to have a separate function fn def_id. I don't like this as a final state here and unlike skip_norm_wip, it's harder to grep for
There was a problem hiding this comment.
yeah... I don't really like probe. Can you always do skip_norm_wf or skip_normalization in cases where we we know that we don't want to normalize
| let (normalized_ty, obligations) = | ||
| self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?; | ||
| let (normalized_ty, obligations) = self.structurally_normalize_ty( | ||
| Unnormalized::new_wip(Ty::new_projection(tcx, trait_target_def_id, [ty])), |
There was a problem hiding this comment.
| Unnormalized::new_wip(Ty::new_projection(tcx, trait_target_def_id, [ty])), | |
| Unnormalized::new(Ty::new_projection(tcx, trait_target_def_id, [ty])), |
very intentionally unnormalized :3
| &ObligationCause::dummy(), | ||
| param_env, | ||
| Ty::new_projection_from_args(infcx.tcx, assoc_item_def_id, args), | ||
| Unnormalized::new_wip(Ty::new_projection_from_args( |
There was a problem hiding this comment.
| Unnormalized::new_wip(Ty::new_projection_from_args( | |
| Unnormalized::new(Ty::new_projection_from_args( |
also very intentionally unnormalized
| cx.typing_env(), | ||
| Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])), | ||
| ) | ||
| && let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), Unnormalized::new_wip(Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])))) |
There was a problem hiding this comment.
can you look through your changes to clippy and avoid breaking formatting as much in your diff? 😅 sorry
| // If is a Future | ||
| && preds | ||
| .iter_instantiated_copied(cx.tcx, args) | ||
| && preds.iter_instantiated_copied(cx.tcx, args).map(Unnormalized::skip_normalization) |
There was a problem hiding this comment.
what are the places that still use skip_normalization instead of skip_norm_wip?
| f(&self.value) | ||
| } | ||
|
|
||
| pub fn map_inner<F, U>(self, f: F) -> Unnormalized<I, U> |
There was a problem hiding this comment.
just call this map
| /// FIXME: Should I just use `skip_normalization`? | ||
| /// Kinda weird to call that insides normalization methods. | ||
| pub fn inside_norm(self) -> T { | ||
| self.value | ||
| } |
There was a problem hiding this comment.
I would call that one skip_normalization and then it should be clear from context why we are 🤔
could imagine being more specific about why we're intentianally not normalizing, but I think for now it's fine for that to be (poorly) implied by the context
| pub fn instantiate_identity(self) -> T { | ||
| self.value | ||
| pub fn instantiate_identity(self) -> Unnormalized<I, T> { | ||
| Unnormalized::new(self.value) |
There was a problem hiding this comment.
| Unnormalized::new(self.value) | |
| // FIXME(#155345): In case the bound value was already normalized, this | |
| // is unnecessary. We may want to track explicitly whether `EarlyBinder` | |
| // contains something that has been normalized already. | |
| // | |
| // This is annoying, as e.g. `type_of` for opaque types is normalized, | |
| // while `type_of` for free type aliases is not. | |
| Unnormalized::new(self.value) |
| .map(Unnormalized::skip_norm_wip) | ||
| .filter_map(ty::Clause::as_trait_clause) |
There was a problem hiding this comment.
| .map(Unnormalized::skip_norm_wip) | |
| .filter_map(ty::Clause::as_trait_clause) | |
| .map(Unnormalized::as_trait_clause) |
| queue.extend( | ||
| tcx.explicit_super_predicates_of(trait_pred.def_id()) | ||
| .iter_identity_copied() | ||
| .map(Unnormalized::skip_norm_wip) |
There was a problem hiding this comment.
explicit_super_predicates_of still does Unnormalized<(Clause, Span)>?
| let trait_ref = trait_ref.skip_norm_wip(); | ||
| ( | ||
| trait_ref.to_host_effect_clause( | ||
| Unnormalized::new_wip(trait_ref.to_host_effect_clause( |
There was a problem hiding this comment.
also add an fn to_host_effect_clause to Unnormalized
| // Don't check non-defaulted params, dependent defaults (including lifetimes) | ||
| // or preds with multiple params. | ||
| if instantiated_pred.has_non_region_param() | ||
| if instantiated_pred.probe(|v| v.has_non_region_param()) |
There was a problem hiding this comment.
why probe over skip_norm_wip?
| .try_normalize_erasing_regions( | ||
| ty::TypingEnv::non_body_analysis(tcx, def_a.did()), | ||
| unnormalized_ty, | ||
| unnormalized_ty.clone(), |
There was a problem hiding this comment.
why .clone? Unnormalized should also be copy 🤔
| .tcx | ||
| .explicit_super_predicates_of(def_id) | ||
| .iter_identity_copied() | ||
| .map(Unnormalized::skip_norm_wip) |
There was a problem hiding this comment.
| .map(Unnormalized::skip_norm_wip) |
|
|
||
| if let Err(reported) = tcx.type_of(start_from_impl).instantiate_identity().error_reported() { | ||
| if let Err(reported) = | ||
| tcx.type_of(start_from_impl).instantiate_identity().skip_norm_wip().error_reported() |
There was a problem hiding this comment.
| tcx.type_of(start_from_impl).instantiate_identity().skip_norm_wip().error_reported() | |
| tcx.type_of(start_from_impl).instantiate_identity().skip_normalization().error_reported() |
intended, don't care about norm
| pub fn probe<F, U>(&self, f: F) -> U | ||
| where | ||
| F: FnOnce(&T) -> U, | ||
| { | ||
| f(&self.value) | ||
| } |
There was a problem hiding this comment.
I would entirely remove this method/is it needed to get something that's copy out of an Unnormalized which is not? 🤔 maybe add as_ref() instead then, as in value.as_ref().skip_normalized().whatever
There was a problem hiding this comment.
Things I'd like to see in this PR maybe?
TypeErrCtxt::normalize_fn_sigshould takeUnnormalized. that should simplify the diffexplicit_item_self_boundsis an iterator overUnnormalized<(Whatever, Span)>, it should also have the span outside of it
Things for future PRs
- I dislike
.map(|(c, s)| (c.skip_norm_wip(), s))as a pattern, we shouldskip_norm_wiponce we iterate over the collection - all of the
t == cx.tcx.normalize_erasing_regions(cx.typing_env(), t)asserts should be someassert_fully_normalizedand don't useUnnormalized::new_wip - a bunch of these normalize calls in codegen are unnecessary. we should change them to use
assert_fully_normalizedinstead - a big one is
struct_tail_rawwhose normalize should take anUnnormalized - all calls to
skip_norm_wip().def_idshould be replaced with adef_id()function onUnnormalized<Whateverhasadefid> - we should add
fn Unnormalized::<T>::map<U>(self, f: impl FnOnce(T) -> U) -> Unnormalized<U> - unsure what to do in
type_ofandpredicates_ofas these queries very intentionally ferry unnormalized types around. I guess we just have a.skip_normalization()for places where it's intentional 🤔 - also slightly unsure about elaborate, I think it should take
Unnormalizedas it also just returns unnormalized things? field.tyshould returnUnnormalizednormalize_with_depth_toshould takeUnnormalized🤔coherence::ImplHeadershould its things beUnnormalizedI think?DropckConstraintshould haveUnnormalizedfields? 🤔- the
DeeplyNormalizeQueryTypeOpshould contain anUnnormalized<T>as input
|
reviewed all changes, and would like to merge this soon 😁 makes it easier to work off it |
View all comments
This is the first step of the eager normalization series.
This PR introduce an
Unnormalizedwrapper and make most normalization routines consume it. The purpose is to make normalization explicit.This PR contains no behavior change.
API changes are in the first two commit.
There're some normalization routines left untouched:
normalizein the type checker of borrowck: better do it together withfield.ty()returningUnnormalized.normalize_with_depth: only used inside the old solver. Can be done later.query_normalize: rarely used.The compiler errors are mostly fixed via
ast-grep, with exceptions handled manually.