diff options
| author | Boxy <rust@boxyuwu.dev> | 2025-06-17 14:45:47 +0100 |
|---|---|---|
| committer | Boxy <rust@boxyuwu.dev> | 2025-06-17 14:48:17 +0100 |
| commit | ae65625252df45569940336bea6df8fe0c4826e6 (patch) | |
| tree | deab875b8ee6e8c0c655fecffb40735fa303b469 | |
| parent | 9961747414891126720b22050f2b049f0e2457c7 (diff) | |
| download | rust-ae65625252df45569940336bea6df8fe0c4826e6.tar.gz rust-ae65625252df45569940336bea6df8fe0c4826e6.zip | |
Dont replace escaping bound vars in item sigs
| -rw-r--r-- | compiler/rustc_hir_analysis/src/collect.rs | 76 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 75 | ||||
| -rw-r--r-- | tests/crashes/138131.rs | 15 | ||||
| -rw-r--r-- | tests/ui/associated-inherent-types/bound_vars_in_args.rs | 3 | ||||
| -rw-r--r-- | tests/ui/associated-inherent-types/bound_vars_in_args.stderr | 41 | ||||
| -rw-r--r-- | tests/ui/associated-inherent-types/issue-109299-1.rs | 4 | ||||
| -rw-r--r-- | tests/ui/associated-inherent-types/issue-109299-1.stderr | 28 |
7 files changed, 82 insertions, 160 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ea4194079a6..176d955bf03 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -380,54 +380,44 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { assert!(!self_ty.has_infer()); // We don't just call the normal normalization routine here as we can't provide the - // correct `ParamEnv` and it seems dubious to invoke arbitrary trait solving under + // correct `ParamEnv` and it would be wrong to invoke arbitrary trait solving under // the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do // this just to make resolution a little bit smarter. let self_ty = self.tcx.expand_free_alias_tys(self_ty); debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty); - // We make an infcx and replace any escaping vars with placeholders so that IAT res - // with type/const bound vars in arguments is slightly smarter. `for<T> <Foo<T>>::IAT` - // would otherwise unify with `impl Foo<u8>` when ideally we would not. - let infcx = self.tcx().infer_ctxt().build(TypingMode::non_body_analysis()); - let mut universes = if self_ty.has_escaping_bound_vars() { - vec![None; self_ty.outer_exclusive_binder().as_usize()] - } else { - vec![] - }; - let candidates = - rustc_trait_selection::traits::with_replaced_escaping_bound_vars( - &infcx, - &mut universes, - self_ty, - |self_ty| { - candidates - .into_iter() - .filter(|&InherentAssocCandidate { impl_, .. }| { - let impl_ty = self.tcx().type_of(impl_).instantiate_identity(); - - // See comment on doing this operation for `self_ty` - let impl_ty = self.tcx.expand_free_alias_tys(impl_ty); - debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty); - - // We treat parameters in the self ty as rigid and parameters in the impl ty as infers - // because it allows `impl<T> Foo<T>` to unify with `Foo<u8>::IAT`, while also disallowing - // `Foo<T>::IAT` from unifying with `impl Foo<u8>`. - // - // We don't really care about a depth limit here because we're only working with user-written - // types and if they wrote a type that would take hours to walk then that's kind of on them. On - // the other hand the default depth limit is relatively low and could realistically be hit by - // users in normal cases. - // - // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases - // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl<T> Foo<T, T>` would - // be considered a valid candidate when resolving `Foo<u8, u16>::IAT`. - ty::DeepRejectCtxt::relate_rigid_infer(self.tcx) - .types_may_unify_with_depth(self_ty, impl_ty, usize::MAX) - }) - .collect() - }, - ); + let candidates = candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + let impl_ty = self.tcx().type_of(impl_).instantiate_identity(); + + // See comment on doing this operation for `self_ty` + let impl_ty = self.tcx.expand_free_alias_tys(impl_ty); + debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty); + + // We treat parameters in the self ty as rigid and parameters in the impl ty as infers + // because it allows `impl<T> Foo<T>` to unify with `Foo<u8>::IAT`, while also disallowing + // `Foo<T>::IAT` from unifying with `impl Foo<u8>`. + // + // We don't really care about a depth limit here because we're only working with user-written + // types and if they wrote a type that would take hours to walk then that's kind of on them. On + // the other hand the default depth limit is relatively low and could realistically be hit by + // users in normal cases. + // + // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases + // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl<T> Foo<T, T>` would + // be considered a valid candidate when resolving `Foo<u8, u16>::IAT`. + // + // Not replacing escaping bound vars in `self_ty` with placeholders also leads to slightly worse + // resolution, but it probably won't come up in practice and it would be backwards compatible + // to switch over to doing that. + ty::DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify_with_depth( + self_ty, + impl_ty, + usize::MAX, + ) + }) + .collect(); (candidates, vec![]) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index d8efb0aac4d..8c18642e54a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -322,6 +322,39 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { ) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) { let tcx = self.tcx(); let infcx = &self.infcx; + let mut fulfillment_errors = vec![]; + + let mut filter_iat_candidate = |self_ty, impl_| { + let ocx = ObligationCtxt::new_with_diagnostics(self); + let self_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, self_ty); + + let impl_args = infcx.fresh_args_for_item(span, impl_); + let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); + let impl_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty); + + // Check that the self types can be related. + if ocx.eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty).is_err() { + return false; + } + + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); + let impl_bounds = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_bounds); + let impl_obligations = traits::predicates_for_generics( + |_, _| ObligationCause::dummy(), + self.param_env, + impl_bounds, + ); + ocx.register_obligations(impl_obligations); + + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return false; + } + + true + }; let mut universes = if self_ty.has_escaping_bound_vars() { vec![None; self_ty.outer_exclusive_binder().as_usize()] @@ -329,52 +362,12 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { vec![] }; - let mut fulfillment_errors = vec![]; let candidates = traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| { candidates .into_iter() .filter(|&InherentAssocCandidate { impl_, .. }| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_with_diagnostics(self); - let self_ty = - ocx.normalize(&ObligationCause::dummy(), self.param_env, self_ty); - - let impl_args = infcx.fresh_args_for_item(span, impl_); - let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); - let impl_ty = - ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty); - - // Check that the self types can be related. - if ocx - .eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty) - .is_err() - { - return false; - } - - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = ocx.normalize( - &ObligationCause::dummy(), - self.param_env, - impl_bounds, - ); - let impl_obligations = traits::predicates_for_generics( - |_, _| ObligationCause::dummy(), - self.param_env, - impl_bounds, - ); - ocx.register_obligations(impl_obligations); - - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return false; - } - - true - }) + infcx.probe(|_| filter_iat_candidate(self_ty, impl_)) }) .collect() }); diff --git a/tests/crashes/138131.rs b/tests/crashes/138131.rs deleted file mode 100644 index d0f91b74840..00000000000 --- a/tests/crashes/138131.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #138131 - -#![feature(min_generic_const_args, generic_const_items)] - -const BAR<'a>: usize = 10; - -struct Foo<'a> { - x: &'a (), -} - -impl<'a> Foo<'a> { - fn foo(_: [u8; BAR]) {} -} - -fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.rs b/tests/ui/associated-inherent-types/bound_vars_in_args.rs index 276e3cf1da0..0baa242af76 100644 --- a/tests/ui/associated-inherent-types/bound_vars_in_args.rs +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.rs @@ -15,9 +15,8 @@ impl<T: Sized> Foo<T> { } struct Bar -//~^ ERROR: the size for values of type `T` cannot be known at compilation time -//~| ERROR: the size for values of type `T` cannot be known at compilation time where for<T> Foo<T>::IAT: Sized; + //~^ ERROR: multiple applicable items in scope fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.stderr b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr index 108f1e531af..9e880476f6a 100644 --- a/tests/ui/associated-inherent-types/bound_vars_in_args.stderr +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr @@ -1,37 +1,20 @@ -error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bound_vars_in_args.rs:17:1 +error[E0034]: multiple applicable items in scope + --> $DIR/bound_vars_in_args.rs:19:20 | -LL | struct Bar - | ^^^^^^^^^^ doesn't have a size known at compile-time +LL | for<T> Foo<T>::IAT: Sized; + | ^^^ multiple `IAT` found | - = help: the trait `Sized` is not implemented for `T` -note: required by a bound in `Foo<T>::IAT` - --> $DIR/bound_vars_in_args.rs:13:9 +note: candidate #1 is defined in an impl for the type `Foo<[u8]>` + --> $DIR/bound_vars_in_args.rs:10:5 | -LL | impl<T: Sized> Foo<T> { - | ^^^^^ required by this bound in `Foo<T>::IAT` LL | type IAT = u8; - | --- required by a bound in this associated type - -error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bound_vars_in_args.rs:17:1 - | -LL | / struct Bar -LL | | -LL | | -LL | | where -LL | | for<T> Foo<T>::IAT: Sized; - | |______________________________^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `T` -note: required by a bound in `Foo<T>::IAT` - --> $DIR/bound_vars_in_args.rs:13:9 + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<T>` + --> $DIR/bound_vars_in_args.rs:14:5 | -LL | impl<T: Sized> Foo<T> { - | ^^^^^ required by this bound in `Foo<T>::IAT` LL | type IAT = u8; - | --- required by a bound in this associated type + | ^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs index 4546785f0b1..3132d9fef69 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.rs +++ b/tests/ui/associated-inherent-types/issue-109299-1.rs @@ -8,8 +8,6 @@ impl Lexer<i32> { } type X = impl for<T> Fn() -> Lexer<T>::Cursor; -//~^ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope -//~| ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope -//~| ERROR: unconstrained opaque type +//~^ ERROR: unconstrained opaque type fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr index 6bc7a539680..bc8ea6acf28 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.stderr +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -6,31 +6,5 @@ LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; | = note: `X` must be used in combination with a concrete type within the same crate -error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope - --> $DIR/issue-109299-1.rs:10:40 - | -LL | struct Lexer<T>(T); - | --------------- associated type `Cursor` not found for this struct -... -LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; - | ^^^^^^ associated item not found in `Lexer<T>` - | - = note: the associated type was found for - - `Lexer<i32>` - -error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope - --> $DIR/issue-109299-1.rs:10:40 - | -LL | struct Lexer<T>(T); - | --------------- associated type `Cursor` not found for this struct -... -LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; - | ^^^^^^ associated item not found in `Lexer<T>` - | - = note: the associated type was found for - - `Lexer<i32>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0220`. |
