From 2d602ea7931ca6988a34567d9255a10c09d0e17e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 3 Jan 2025 05:01:14 +0000 Subject: [PATCH 1/2] Do not project when there are unconstrained impl params --- .../rustc_hir_analysis/src/impl_wf_check.rs | 123 +++++++++++++----- compiler/rustc_hir_analysis/src/lib.rs | 2 + compiler/rustc_middle/src/query/mod.rs | 5 + .../src/traits/project.rs | 63 ++++----- .../traits/specialize/specialization_graph.rs | 14 ++ tests/crashes/123141.rs | 23 ---- tests/crashes/125874.rs | 22 ---- tests/crashes/126942.rs | 11 -- tests/crashes/127804.rs | 12 -- tests/crashes/130967.rs | 13 -- .../bugs/issue-87735.stderr | 68 +--------- .../in-trait/refine-resolution-errors.rs | 1 - .../in-trait/refine-resolution-errors.stderr | 11 +- tests/ui/impl-trait/issues/issue-87340.rs | 2 - tests/ui/impl-trait/issues/issue-87340.stderr | 17 +-- tests/ui/impl-unused-tps.stderr | 12 +- ...nconstrained-projection-normalization-2.rs | 17 +++ ...strained-projection-normalization-2.stderr | 9 ++ .../unconstrained-projection-normalization.rs | 16 +++ ...onstrained-projection-normalization.stderr | 9 ++ ...e-failed-to-resolve-instance-for-110696.rs | 1 - ...iled-to-resolve-instance-for-110696.stderr | 15 +-- .../impl-with-unconstrained-param.rs | 2 - .../impl-with-unconstrained-param.stderr | 17 +-- tests/ui/type-alias-impl-trait/issue-74244.rs | 1 - .../type-alias-impl-trait/issue-74244.stderr | 11 +- 26 files changed, 214 insertions(+), 283 deletions(-) delete mode 100644 tests/crashes/123141.rs delete mode 100644 tests/crashes/125874.rs delete mode 100644 tests/crashes/126942.rs delete mode 100644 tests/crashes/127804.rs delete mode 100644 tests/crashes/130967.rs create mode 100644 tests/ui/traits/unconstrained-projection-normalization-2.rs create mode 100644 tests/ui/traits/unconstrained-projection-normalization-2.stderr create mode 100644 tests/ui/traits/unconstrained-projection-normalization.rs create mode 100644 tests/ui/traits/unconstrained-projection-normalization.stderr diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index d9c70c3cee655..bb122009593b9 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -57,22 +57,24 @@ pub(crate) fn check_impl_wf( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - let min_specialization = tcx.features().min_specialization(); - let mut res = Ok(()); debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. }); - res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id)); - if min_specialization { + + // Check that the args are constrained. We queryfied the check for ty/const params + // since unconstrained type/const params cause ICEs in projection, so we want to + // detect those specifically and project those to `TyKind::Error`. + let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id); + res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id)); + + if tcx.features().min_specialization() { res = res.and(check_min_specialization(tcx, impl_def_id)); } - res } -fn enforce_impl_params_are_constrained( +pub(crate) fn enforce_impl_lifetime_params_are_constrained( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - // Every lifetime used in an associated type must be constrained. let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); if impl_self_ty.references_error() { // Don't complain about unconstrained type params when self ty isn't known due to errors. @@ -88,6 +90,7 @@ fn enforce_impl_params_are_constrained( // Compilation must continue in order for other important diagnostics to keep showing up. return Ok(()); } + let impl_generics = tcx.generics_of(impl_def_id); let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity); @@ -121,6 +124,84 @@ fn enforce_impl_params_are_constrained( }) .collect(); + let mut res = Ok(()); + for param in &impl_generics.own_params { + match param.kind { + ty::GenericParamDefKind::Lifetime => { + let param_lt = cgp::Parameter::from(param.to_early_bound_region_data()); + if lifetimes_in_associated_types.contains(¶m_lt) // (*) + && !input_parameters.contains(¶m_lt) + { + let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter { + span: tcx.def_span(param.def_id), + param_name: param.name, + param_def_kind: tcx.def_descr(param.def_id), + const_param_note: false, + const_param_note2: false, + }); + diag.code(E0207); + res = Err(diag.emit()); + } + // (*) This is a horrible concession to reality. I think it'd be + // better to just ban unconstrained lifetimes outright, but in + // practice people do non-hygienic macros like: + // + // ``` + // macro_rules! __impl_slice_eq1 { + // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + // .... + // } + // } + // } + // ``` + // + // In a concession to backwards compatibility, we continue to + // permit those, so long as the lifetimes aren't used in + // associated types. I believe this is sound, because lifetimes + // used elsewhere are not projected back out. + } + ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => { + // Enforced in `enforce_impl_non_lifetime_params_are_constrained`. + } + } + } + res +} + +pub(crate) fn enforce_impl_non_lifetime_params_are_constrained( + tcx: TyCtxt<'_>, + impl_def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { + let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity(); + if impl_self_ty.references_error() { + // Don't complain about unconstrained type params when self ty isn't known due to errors. + // (#36836) + tcx.dcx().span_delayed_bug( + tcx.def_span(impl_def_id), + format!( + "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}", + ), + ); + // This is super fishy, but our current `rustc_hir_analysis::check_crate` pipeline depends on + // `type_of` having been called much earlier, and thus this value being read from cache. + // Compilation must continue in order for other important diagnostics to keep showing up. + return Ok(()); + } + let impl_generics = tcx.generics_of(impl_def_id); + let impl_predicates = tcx.predicates_of(impl_def_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity); + + impl_trait_ref.error_reported()?; + + let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref); + cgp::identify_constrained_generic_params( + tcx, + impl_predicates, + impl_trait_ref, + &mut input_parameters, + ); + let mut res = Ok(()); for param in &impl_generics.own_params { let err = match param.kind { @@ -129,15 +210,14 @@ fn enforce_impl_params_are_constrained( let param_ty = ty::ParamTy::for_def(param); !input_parameters.contains(&cgp::Parameter::from(param_ty)) } - ty::GenericParamDefKind::Lifetime => { - let param_lt = cgp::Parameter::from(param.to_early_bound_region_data()); - lifetimes_in_associated_types.contains(¶m_lt) && // (*) - !input_parameters.contains(¶m_lt) - } ty::GenericParamDefKind::Const { .. } => { let param_ct = ty::ParamConst::for_def(param); !input_parameters.contains(&cgp::Parameter::from(param_ct)) } + ty::GenericParamDefKind::Lifetime => { + // Enforced in `enforce_impl_type_params_are_constrained`. + false + } }; if err { let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. }); @@ -153,23 +233,4 @@ fn enforce_impl_params_are_constrained( } } res - - // (*) This is a horrible concession to reality. I think it'd be - // better to just ban unconstrained lifetimes outright, but in - // practice people do non-hygienic macros like: - // - // ``` - // macro_rules! __impl_slice_eq1 { - // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { - // .... - // } - // } - // } - // ``` - // - // In a concession to backwards compatibility, we continue to - // permit those, so long as the lifetimes aren't used in - // associated types. I believe this is sound, because lifetimes - // used elsewhere are not projected back out. } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 87fd4de26a5af..a42a168234f07 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -128,6 +128,8 @@ pub fn provide(providers: &mut Providers) { hir_wf_check::provide(providers); *providers = Providers { inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item, + enforce_impl_non_lifetime_params_are_constrained: + impl_wf_check::enforce_impl_non_lifetime_params_are_constrained, ..*providers }; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7e7b602c560ba..8b8467472f54b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1719,6 +1719,11 @@ rustc_queries! { ensure_forwards_result_if_red } + query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> { + desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) } + ensure_forwards_result_if_red + } + // The `DefId`s of all non-generic functions and statics in the given crate // that can be reached from outside the crate. // diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 54407d17dcf0f..69b7d5cff1e00 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -950,39 +950,45 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // // NOTE: This should be kept in sync with the similar code in // `rustc_ty_utils::instance::resolve_associated_item()`. - let node_item = specialization_graph::assoc_def( + match specialization_graph::assoc_def( selcx.tcx(), impl_data.impl_def_id, obligation.predicate.def_id, - ) - .map_err(|ErrorGuaranteed { .. }| ())?; - - if node_item.is_final() { - // Non-specializable items are always projectable. - true - } else { - // Only reveal a specializable default if we're past type-checking - // and the obligation is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - match selcx.infcx.typing_mode() { - TypingMode::Coherence - | TypingMode::Analysis { .. } - | TypingMode::PostBorrowckAnalysis { .. } => { - debug!( - assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), - ?obligation.predicate, - "assemble_candidates_from_impls: not eligible due to default", - ); - false - } - TypingMode::PostAnalysis => { - // NOTE(eddyb) inference variables can resolve to parameters, so - // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref); - !poly_trait_ref.still_further_specializable() + ) { + Ok(node_item) => { + if node_item.is_final() { + // Non-specializable items are always projectable. + true + } else { + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + match selcx.infcx.typing_mode() { + TypingMode::Coherence + | TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } => { + debug!( + assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), + ?obligation.predicate, + "not eligible due to default", + ); + false + } + TypingMode::PostAnalysis => { + // NOTE(eddyb) inference variables can resolve to parameters, so + // assume `poly_trait_ref` isn't monomorphic, if it contains any. + let poly_trait_ref = + selcx.infcx.resolve_vars_if_possible(trait_ref); + !poly_trait_ref.still_further_specializable() + } + } } } + // Always project `ErrorGuaranteed`, since this will just help + // us propagate `TyKind::Error` around which suppresses ICEs + // and spurious, unrelated inference errors. + Err(ErrorGuaranteed { .. }) => true, } } ImplSource::Builtin(BuiltinImplSource::Misc, _) => { @@ -2014,7 +2020,6 @@ fn confirm_impl_candidate<'cx, 'tcx>( Ok(assoc_ty) => assoc_ty, Err(guar) => return Progress::error(tcx, guar), }; - if !assoc_ty.item.defaultness(tcx).has_value() { // This means that the impl is missing a definition for the // associated type. This error will be reported by the type diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 13620f4b8d9cc..c351cf5aaac61 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -376,6 +376,12 @@ pub(crate) fn assoc_def( // If there is no such item in that impl, this function will fail with a // cycle error if the specialization graph is currently being built. if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) { + // Ensure that the impl is constrained, otherwise projection may give us + // bad unconstrained infer vars. + if let Some(impl_def_id) = impl_def_id.as_local() { + tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; + } + let item = tcx.associated_item(impl_item_id); let impl_node = Node::Impl(impl_def_id); return Ok(LeafDef { @@ -391,6 +397,14 @@ pub(crate) fn assoc_def( let ancestors = trait_def.ancestors(tcx, impl_def_id)?; if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) { + // Ensure that the impl is constrained, otherwise projection may give us + // bad unconstrained infer vars. + if assoc_item.item.container == ty::AssocItemContainer::Impl + && let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local() + { + tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; + } + Ok(assoc_item) } else { // This is saying that neither the trait nor diff --git a/tests/crashes/123141.rs b/tests/crashes/123141.rs deleted file mode 100644 index 07181387e0450..0000000000000 --- a/tests/crashes/123141.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ known-bug: #123141 - -trait Trait { - fn next(self) -> Self::Item; - type Item; -} - -struct Foo(T); - -impl Trait for Foo { - type Item = Foo; - fn next(self) -> Self::Item { - loop {} - } -} - -fn opaque() -> impl Trait { - Foo::<_>(10_u32) -} - -fn main() { - opaque().next(); -} diff --git a/tests/crashes/125874.rs b/tests/crashes/125874.rs deleted file mode 100644 index 6a2713cd7c896..0000000000000 --- a/tests/crashes/125874.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: rust-lang/rust#125874 -pub trait A {} - -pub trait Mirror { - type Assoc: ?Sized; -} -impl Mirror for dyn A { - type Assoc = T; -} - -struct Bar { - foo: ::Assoc, -} - -pub fn main() { - let strct = Bar { foo: 3 }; - - match strct { - Bar { foo: 1, .. } => {} - _ => (), - }; -} diff --git a/tests/crashes/126942.rs b/tests/crashes/126942.rs deleted file mode 100644 index e4adc8fab287e..0000000000000 --- a/tests/crashes/126942.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#126942 -struct Thing; - -pub trait Every { - type Assoc; -} -impl Every for Thing { - type Assoc = T; -} - -static I: ::Assoc = 3; diff --git a/tests/crashes/127804.rs b/tests/crashes/127804.rs deleted file mode 100644 index e583a7c1fc650..0000000000000 --- a/tests/crashes/127804.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #127804 - -struct Thing; - -pub trait Every { - type Assoc; -} -impl Every for Thing { - type Assoc = T; -} - -fn foo(_: ::Assoc) {} diff --git a/tests/crashes/130967.rs b/tests/crashes/130967.rs deleted file mode 100644 index 8a3aae72c20c5..0000000000000 --- a/tests/crashes/130967.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #130967 - -trait Producer { - type Produced; - fn make_one() -> Self::Produced; -} - -impl Producer for () { - type Produced = Option; - fn make_one() -> Self::Produced { - loop {} - } -} diff --git a/tests/ui/generic-associated-types/bugs/issue-87735.stderr b/tests/ui/generic-associated-types/bugs/issue-87735.stderr index d80050652389d..1b95543136303 100644 --- a/tests/ui/generic-associated-types/bugs/issue-87735.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-87735.stderr @@ -22,73 +22,7 @@ help: consider adding an explicit lifetime bound LL | type Output<'a> = FooRef<'a, U> where Self: 'a, U: 'a; | +++++++ -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/issue-87735.rs:31:15 - | -LL | impl<'b, T, U> AsRef2 for Foo - | -- the parameter type `T` must be valid for the lifetime `'b` as defined here... -... -LL | T: AsRef2 = &'b [U]>, - | ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... - | -note: ...that is required by this bound - --> $DIR/issue-87735.rs:7:31 - | -LL | type Output<'a> where Self: 'a; - | ^^ -help: consider adding an explicit lifetime bound - | -LL | T: AsRef2 = &'b [U]> + 'b, - | ++++ - -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/issue-87735.rs:36:31 - | -LL | impl<'b, T, U> AsRef2 for Foo - | -- the parameter type `T` must be valid for the lifetime `'b` as defined here... -... -LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> { - | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... - | -note: ...that is required by this bound - --> $DIR/issue-87735.rs:7:31 - | -LL | type Output<'a> where Self: 'a; - | ^^ -help: consider adding an explicit lifetime bound - | -LL | T: AsRef2 = &'b [U]> + 'b, - | ++++ - -error: lifetime may not live long enough - --> $DIR/issue-87735.rs:37:5 - | -LL | impl<'b, T, U> AsRef2 for Foo - | -- lifetime `'b` defined here -... -LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> { - | -- lifetime `'a` defined here -LL | FooRef(self.0.as_ref2()) - | ^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` - | - = help: consider adding the following bound: `'b: 'a` - -error: lifetime may not live long enough - --> $DIR/issue-87735.rs:37:12 - | -LL | impl<'b, T, U> AsRef2 for Foo - | -- lifetime `'b` defined here -... -LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> { - | -- lifetime `'a` defined here -LL | FooRef(self.0.as_ref2()) - | ^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b` - | - = help: consider adding the following bound: `'a: 'b` - -help: `'b` and `'a` must be the same: replace one with the other - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0207, E0309. For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs index a9936c7bc3fee..894f592d9e204 100644 --- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs @@ -13,7 +13,6 @@ impl Mirror for () { pub trait First { async fn first() -> <() as Mirror>::Assoc; - //~^ ERROR type annotations needed } impl First for () { diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr index 0f5573dda04c1..10ebad2a7d5a1 100644 --- a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr @@ -4,13 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self LL | impl Mirror for () { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/refine-resolution-errors.rs:15:5 - | -LL | async fn first() -> <() as Mirror>::Assoc; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-trait/issues/issue-87340.rs b/tests/ui/impl-trait/issues/issue-87340.rs index b1baaaa6ba5c1..705a4addcb704 100644 --- a/tests/ui/impl-trait/issues/issue-87340.rs +++ b/tests/ui/impl-trait/issues/issue-87340.rs @@ -9,8 +9,6 @@ impl X for () { //~^ ERROR `T` is not constrained by the impl trait, self type, or predicates type I = impl Sized; fn f() -> Self::I {} - //~^ ERROR type annotations needed - //~| ERROR type annotations needed } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-87340.stderr b/tests/ui/impl-trait/issues/issue-87340.stderr index 1be4087be4242..8513cb2881e1f 100644 --- a/tests/ui/impl-trait/issues/issue-87340.stderr +++ b/tests/ui/impl-trait/issues/issue-87340.stderr @@ -4,19 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self LL | impl X for () { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/issue-87340.rs:11:23 - | -LL | fn f() -> Self::I {} - | ^^ cannot infer type for type parameter `T` - -error[E0282]: type annotations needed - --> $DIR/issue-87340.rs:11:15 - | -LL | fn f() -> Self::I {} - | ^^^^^^^ cannot infer type for type parameter `T` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/impl-unused-tps.stderr index da4589dee8278..09c3fce641cfe 100644 --- a/tests/ui/impl-unused-tps.stderr +++ b/tests/ui/impl-unused-tps.stderr @@ -7,6 +7,12 @@ LL | impl Foo for [isize; 0] { LL | impl Foo for U { | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]` +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/impl-unused-tps.rs:32:9 + | +LL | impl Bar for T { + | ^ unconstrained type parameter + error[E0119]: conflicting implementations of trait `Bar` --> $DIR/impl-unused-tps.rs:40:1 | @@ -46,12 +52,6 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self LL | impl Foo for [isize; 1] { | ^ unconstrained type parameter -error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:32:9 - | -LL | impl Bar for T { - | ^ unconstrained type parameter - error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates --> $DIR/impl-unused-tps.rs:40:9 | diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.rs b/tests/ui/traits/unconstrained-projection-normalization-2.rs new file mode 100644 index 0000000000000..085e9e4a61a8e --- /dev/null +++ b/tests/ui/traits/unconstrained-projection-normalization-2.rs @@ -0,0 +1,17 @@ +// Make sure we don't ICE in `normalize_erasing_regions` when normalizing +// an associated type in an impl with unconstrained non-lifetime params. +// (This time in a function signature) + +struct Thing; + +pub trait Every { + type Assoc; +} +impl Every for Thing { +//~^ ERROR the type parameter `T` is not constrained + type Assoc = T; +} + +fn foo(_: ::Assoc) {} + +fn main() {} diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.stderr b/tests/ui/traits/unconstrained-projection-normalization-2.stderr new file mode 100644 index 0000000000000..6d3d4492b0775 --- /dev/null +++ b/tests/ui/traits/unconstrained-projection-normalization-2.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-projection-normalization-2.rs:10:6 + | +LL | impl Every for Thing { + | ^ unconstrained type parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/traits/unconstrained-projection-normalization.rs b/tests/ui/traits/unconstrained-projection-normalization.rs new file mode 100644 index 0000000000000..e4d25a5ba6c6f --- /dev/null +++ b/tests/ui/traits/unconstrained-projection-normalization.rs @@ -0,0 +1,16 @@ +// Make sure we don't ICE in `normalize_erasing_regions` when normalizing +// an associated type in an impl with unconstrained non-lifetime params. + +struct Thing; + +pub trait Every { + type Assoc; +} +impl Every for Thing { +//~^ ERROR the type parameter `T` is not constrained + type Assoc = T; +} + +static I: ::Assoc = 3; + +fn main() {} diff --git a/tests/ui/traits/unconstrained-projection-normalization.stderr b/tests/ui/traits/unconstrained-projection-normalization.stderr new file mode 100644 index 0000000000000..4e4421a73e506 --- /dev/null +++ b/tests/ui/traits/unconstrained-projection-normalization.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-projection-normalization.rs:9:6 + | +LL | impl Every for Thing { + | ^ unconstrained type parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs index 0ee188d825f0d..2bcb8f06f4fd6 100644 --- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs +++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs @@ -42,7 +42,6 @@ impl>>, U> MyIndex> for Scope { //~^ ERROR the type parameter `T` is not constrained by the impl type O = T; fn my_index(self) -> Self::O { - //~^ ERROR item does not constrain MyFrom::my_from(self.0).ok().unwrap() } } diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr index eace96317dc1d..0ab4c34381a26 100644 --- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr +++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr @@ -17,19 +17,6 @@ note: this opaque type is in the signature LL | type DummyT = impl F; | ^^^^^^ -error: item does not constrain `DummyT::{opaque#0}`, but has it in its signature - --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:44:8 - | -LL | fn my_index(self) -> Self::O { - | ^^^^^^^^ - | - = note: consider moving the opaque type's declaration and defining uses into a separate module -note: this opaque type is in the signature - --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:20:18 - | -LL | type DummyT = impl F; - | ^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs index fcac83500ec4f..1824ff5e2fb82 100644 --- a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs +++ b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs @@ -12,8 +12,6 @@ impl X for () { //~^ ERROR the type parameter `T` is not constrained type I = impl Sized; fn f() -> Self::I {} - //~^ ERROR type annotations needed - //~| ERROR type annotations needed } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr index bb0e11d314c33..137a4db81b563 100644 --- a/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr +++ b/tests/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr @@ -4,19 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self LL | impl X for () { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/impl-with-unconstrained-param.rs:14:23 - | -LL | fn f() -> Self::I {} - | ^^ cannot infer type for type parameter `T` - -error[E0282]: type annotations needed - --> $DIR/impl-with-unconstrained-param.rs:14:15 - | -LL | fn f() -> Self::I {} - | ^^^^^^^ cannot infer type for type parameter `T` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/type-alias-impl-trait/issue-74244.rs b/tests/ui/type-alias-impl-trait/issue-74244.rs index ce8a38a3361f8..bb4104b3d2519 100644 --- a/tests/ui/type-alias-impl-trait/issue-74244.rs +++ b/tests/ui/type-alias-impl-trait/issue-74244.rs @@ -14,7 +14,6 @@ impl Allocator for DefaultAllocator { type A = impl Fn(::Buffer); fn foo() -> A { - //~^ ERROR: type annotations needed |_| () } diff --git a/tests/ui/type-alias-impl-trait/issue-74244.stderr b/tests/ui/type-alias-impl-trait/issue-74244.stderr index d2b50ffd86b59..f5ca56bacccf6 100644 --- a/tests/ui/type-alias-impl-trait/issue-74244.stderr +++ b/tests/ui/type-alias-impl-trait/issue-74244.stderr @@ -4,13 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self LL | impl Allocator for DefaultAllocator { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/issue-74244.rs:16:13 - | -LL | fn foo() -> A { - | ^ cannot infer type for type parameter `T` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. From 7143ef6550f501083bcf6e8b516bb1ae3e191d29 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 3 Jan 2025 05:22:14 +0000 Subject: [PATCH 2/2] Also in the new solver --- .../rustc_next_trait_solver/src/delegate.rs | 5 ++- .../src/solve/eval_ctxt/mod.rs | 2 +- .../src/solve/normalizes_to/mod.rs | 38 +++++++++++-------- .../src/solve/delegate.rs | 5 +-- ...projection-normalization-2.current.stderr} | 2 +- ...ned-projection-normalization-2.next.stderr | 9 +++++ ...nconstrained-projection-normalization-2.rs | 4 ++ ...d-projection-normalization.current.stderr} | 2 +- ...ained-projection-normalization.next.stderr | 9 +++++ .../unconstrained-projection-normalization.rs | 4 ++ 10 files changed, 57 insertions(+), 23 deletions(-) rename tests/ui/traits/{unconstrained-projection-normalization-2.stderr => unconstrained-projection-normalization-2.current.stderr} (83%) create mode 100644 tests/ui/traits/unconstrained-projection-normalization-2.next.stderr rename tests/ui/traits/{unconstrained-projection-normalization.stderr => unconstrained-projection-normalization.current.stderr} (83%) create mode 100644 tests/ui/traits/unconstrained-projection-normalization.next.stderr diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 4ba54a2e0bf23..2d2d50e62f9a1 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -95,7 +95,10 @@ pub trait SolverDelegate: Deref::Infcx> + Size goal_trait_ref: ty::TraitRef, trait_assoc_def_id: ::DefId, impl_def_id: ::DefId, - ) -> Result::DefId>, NoSolution>; + ) -> Result< + Option<::DefId>, + ::ErrorGuaranteed, + >; fn is_transmutable( &self, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8c74490e0e0ee..91ad24bff6743 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -950,7 +950,7 @@ where goal_trait_ref: ty::TraitRef, trait_assoc_def_id: I::DefId, impl_def_id: I::DefId, - ) -> Result, NoSolution> { + ) -> Result, I::ErrorGuaranteed> { self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id) } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index f5ecfea540858..76cbe5758b23a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -244,20 +244,7 @@ where .map(|pred| goal.with(cx, pred)), ); - // In case the associated item is hidden due to specialization, we have to - // return ambiguity this would otherwise be incomplete, resulting in - // unsoundness during coherence (#105782). - let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item( - goal_trait_ref, - goal.predicate.def_id(), - impl_def_id, - )? - else { - return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - }; - - let error_response = |ecx: &mut EvalCtxt<'_, D>, msg: &str| { - let guar = cx.delay_bug(msg); + let error_response = |ecx: &mut EvalCtxt<'_, D>, guar| { let error_term = match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy => Ty::new_error(cx, guar).into(), ty::AliasTermKind::ProjectionConst => Const::new_error(cx, guar).into(), @@ -267,8 +254,24 @@ where ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }; + // In case the associated item is hidden due to specialization, we have to + // return ambiguity this would otherwise be incomplete, resulting in + // unsoundness during coherence (#105782). + let target_item_def_id = match ecx.fetch_eligible_assoc_item( + goal_trait_ref, + goal.predicate.def_id(), + impl_def_id, + ) { + Ok(Some(target_item_def_id)) => target_item_def_id, + Ok(None) => { + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + Err(guar) => return error_response(ecx, guar), + }; + if !cx.has_item_definition(target_item_def_id) { - return error_response(ecx, "missing item"); + return error_response(ecx, cx.delay_bug("missing item")); } let target_container_def_id = cx.parent(target_item_def_id); @@ -292,7 +295,10 @@ where )?; if !cx.check_args_compatible(target_item_def_id, target_args) { - return error_response(ecx, "associated item has mismatched arguments"); + return error_response( + ecx, + cx.delay_bug("associated item has mismatched arguments"), + ); } // Finally we construct the actual value of the associated type. diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 9b8c9ff6bb834..acd00d9f74f56 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -190,9 +190,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< goal_trait_ref: ty::TraitRef<'tcx>, trait_assoc_def_id: DefId, impl_def_id: DefId, - ) -> Result, NoSolution> { - let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id) - .map_err(|ErrorGuaranteed { .. }| NoSolution)?; + ) -> Result, ErrorGuaranteed> { + let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id)?; let eligible = if node_item.is_final() { // Non-specializable items are always projectable. diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.stderr b/tests/ui/traits/unconstrained-projection-normalization-2.current.stderr similarity index 83% rename from tests/ui/traits/unconstrained-projection-normalization-2.stderr rename to tests/ui/traits/unconstrained-projection-normalization-2.current.stderr index 6d3d4492b0775..2bb389c6ec161 100644 --- a/tests/ui/traits/unconstrained-projection-normalization-2.stderr +++ b/tests/ui/traits/unconstrained-projection-normalization-2.current.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-projection-normalization-2.rs:10:6 + --> $DIR/unconstrained-projection-normalization-2.rs:14:6 | LL | impl Every for Thing { | ^ unconstrained type parameter diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr b/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr new file mode 100644 index 0000000000000..2bb389c6ec161 --- /dev/null +++ b/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-projection-normalization-2.rs:14:6 + | +LL | impl Every for Thing { + | ^ unconstrained type parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.rs b/tests/ui/traits/unconstrained-projection-normalization-2.rs index 085e9e4a61a8e..6b584c436c606 100644 --- a/tests/ui/traits/unconstrained-projection-normalization-2.rs +++ b/tests/ui/traits/unconstrained-projection-normalization-2.rs @@ -2,6 +2,10 @@ // an associated type in an impl with unconstrained non-lifetime params. // (This time in a function signature) +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + struct Thing; pub trait Every { diff --git a/tests/ui/traits/unconstrained-projection-normalization.stderr b/tests/ui/traits/unconstrained-projection-normalization.current.stderr similarity index 83% rename from tests/ui/traits/unconstrained-projection-normalization.stderr rename to tests/ui/traits/unconstrained-projection-normalization.current.stderr index 4e4421a73e506..991f0e8ba666e 100644 --- a/tests/ui/traits/unconstrained-projection-normalization.stderr +++ b/tests/ui/traits/unconstrained-projection-normalization.current.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-projection-normalization.rs:9:6 + --> $DIR/unconstrained-projection-normalization.rs:13:6 | LL | impl Every for Thing { | ^ unconstrained type parameter diff --git a/tests/ui/traits/unconstrained-projection-normalization.next.stderr b/tests/ui/traits/unconstrained-projection-normalization.next.stderr new file mode 100644 index 0000000000000..991f0e8ba666e --- /dev/null +++ b/tests/ui/traits/unconstrained-projection-normalization.next.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-projection-normalization.rs:13:6 + | +LL | impl Every for Thing { + | ^ unconstrained type parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/traits/unconstrained-projection-normalization.rs b/tests/ui/traits/unconstrained-projection-normalization.rs index e4d25a5ba6c6f..fa4ab7fec4c2f 100644 --- a/tests/ui/traits/unconstrained-projection-normalization.rs +++ b/tests/ui/traits/unconstrained-projection-normalization.rs @@ -1,6 +1,10 @@ // Make sure we don't ICE in `normalize_erasing_regions` when normalizing // an associated type in an impl with unconstrained non-lifetime params. +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + struct Thing; pub trait Every {