diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index bee062b27e0f5..e449e9d7c59a0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -585,6 +585,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &[path_str], item_segment.ident, assoc_tag, + Applicability::MachineApplicable, ) } @@ -698,6 +699,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &traits, ident, assoc_tag, + Applicability::MaybeIncorrect, ) } } @@ -709,6 +711,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { traits: &[String], ident: Ident, assoc_tag: ty::AssocTag, + applicability: Applicability, ) -> ErrorGuaranteed { let kind_str = assoc_tag_str(assoc_tag); let mut err = @@ -807,7 +810,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { sugg_sp, "use fully-qualified syntax", suggestions, - Applicability::MachineApplicable, + applicability, SuggestionStyle::ShowAlways, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index e9dc2a61d698d..8e5c33f5d4f16 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -37,7 +37,7 @@ use rustc_errors::{ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::DynCompatibilityViolation; use rustc_lint_defs::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_macros::{TypeFoldable, TypeVisitable}; @@ -45,13 +45,11 @@ use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::consts::ConstExt; use rustc_middle::ty::{ self, Const, FnSigKind, GenericArgKind, GenericArgsRef, GenericParamDefKind, LitToConstInput, - Ty, TyCtxt, TypeSuperFoldable, TypeVisitableExt, TypingMode, Unnormalized, Upcast, - const_lit_matches_ty, fold_regions, + Ty, TyCtxt, TypeSuperFoldable, TypeVisitableExt, Unnormalized, Upcast, const_lit_matches_ty, }; use rustc_session::diagnostics::feature_err; use rustc_span::def_id::{LocalModId, ModId}; -use rustc_span::{DUMMY_SP, Ident, Span, bug, kw, span_bug, sym}; -use rustc_trait_selection::infer::InferCtxtExt; +use rustc_span::{Ident, Span, bug, kw, span_bug, sym}; use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; @@ -1860,16 +1858,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Vec { let tcx = self.tcx(); - // In contexts that have no inference context, just make a new one. - // We do need a local variable to store it, though. - let infcx_; - let infcx = if let Some(infcx) = self.infcx() { - infcx - } else { - assert!(!qself_ty.has_infer()); - infcx_ = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); - &infcx_ - }; + // Deep rejection cannot rule out unrelated impls for unresolved aliases. + // Avoid offering misleading suggestions for those types. + if qself_ty.has_aliases() { + return Vec::new(); + } + + // FIXME: Support non-lifetime binders without suggesting unrelated traits. + if qself_ty.has_non_region_bound_vars() { + return Vec::new(); + } tcx.all_traits_including_private() .filter(|trait_def_id| { @@ -1887,19 +1885,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { && tcx.all_impls(*trait_def_id) .any(|impl_def_id| { let header = tcx.impl_trait_header(impl_def_id); - let trait_ref = header.trait_ref.instantiate(tcx, infcx.fresh_args_for_item(DUMMY_SP, impl_def_id)).skip_norm_wip(); - - let value = fold_regions(tcx, qself_ty, |_, _| tcx.lifetimes.re_erased); - // FIXME: Don't bother dealing with non-lifetime binders here... - if value.has_escaping_bound_vars() { + if header.polarity == ty::ImplPolarity::Negative { return false; } - infcx - .can_eq( - ty::ParamEnv::empty(), - trait_ref.self_ty(), - value, - ) && header.polarity != ty::ImplPolarity::Negative + + let impl_ty = header + .trait_ref + .instantiate_identity() + .skip_norm_wip() + .self_ty(); + + ty::DeepRejectCtxt::relate_rigid_infer(tcx) + .types_may_unify(qself_ty, impl_ty) }) }) .map(|trait_def_id| tcx.def_path_str(trait_def_id)) diff --git a/tests/ui/traits/next-solver/assoc-ty-const-generics-issue-163320.rs b/tests/ui/traits/next-solver/assoc-ty-const-generics-issue-163320.rs new file mode 100644 index 0000000000000..cc9084ed37ee9 --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-ty-const-generics-issue-163320.rs @@ -0,0 +1,62 @@ +// Regression test for issue #163320: ambiguous associated-type paths +// involving const generics must not ICE during item lowering or type checking. + +//@ compile-flags: -Znext-solver=globally +//@ check-fail + +#![feature(generic_const_parameter_types)] + +fn where_clause() +where + <[(); N] as IntoIterator>::Item::Item:, + //~^ ERROR ambiguous associated type +{} + +fn nested_where() +where + Option<<[(); N] as IntoIterator>::Item::Item>: Sized, + //~^ ERROR ambiguous associated type +{} + +fn parameter( + _: <[(); N] as IntoIterator>::Item::Item, + //~^ ERROR ambiguous associated type +) {} + +type Alias = + <[(); N] as IntoIterator>::Item::Item; +//~^ ERROR ambiguous associated type + +struct Field { + field: <[(); N] as IntoIterator>::Item::Item, + //~^ ERROR ambiguous associated type +} + +struct Parent; + +impl Parent { + fn inherited() + where + <[(); N] as IntoIterator>::Item::Item:, + //~^ ERROR ambiguous associated type + {} +} + +struct ConstParameter< + const N: usize, + const M: <[(); N] as IntoIterator>::Item::Item, + //~^ ERROR ambiguous associated type +>; + +struct TypeParameterDefault< + const N: usize, + T = <[(); N] as IntoIterator>::Item::Item, + //~^ ERROR ambiguous associated type +>(std::marker::PhantomData); + +fn in_body() { + let _: <[(); N] as IntoIterator>::Item::Item; + //~^ ERROR ambiguous associated type +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/assoc-ty-const-generics-issue-163320.stderr b/tests/ui/traits/next-solver/assoc-ty-const-generics-issue-163320.stderr new file mode 100644 index 0000000000000..8d87c85a6ac92 --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-ty-const-generics-issue-163320.stderr @@ -0,0 +1,111 @@ +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:11:5 + | +LL | <[(); N] as IntoIterator>::Item::Item:, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - <[(); N] as IntoIterator>::Item::Item:, +LL + <<[(); N] as IntoIterator>::Item as Example>::Item:, + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:17:12 + | +LL | Option<<[(); N] as IntoIterator>::Item::Item>: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - Option<<[(); N] as IntoIterator>::Item::Item>: Sized, +LL + Option<<<[(); N] as IntoIterator>::Item as Example>::Item>: Sized, + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:22:8 + | +LL | _: <[(); N] as IntoIterator>::Item::Item, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - _: <[(); N] as IntoIterator>::Item::Item, +LL + _: <<[(); N] as IntoIterator>::Item as Example>::Item, + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:27:5 + | +LL | <[(); N] as IntoIterator>::Item::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - <[(); N] as IntoIterator>::Item::Item; +LL + <<[(); N] as IntoIterator>::Item as Example>::Item; + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:31:12 + | +LL | field: <[(); N] as IntoIterator>::Item::Item, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - field: <[(); N] as IntoIterator>::Item::Item, +LL + field: <<[(); N] as IntoIterator>::Item as Example>::Item, + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:47:14 + | +LL | const M: <[(); N] as IntoIterator>::Item::Item, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - const M: <[(); N] as IntoIterator>::Item::Item, +LL + const M: <<[(); N] as IntoIterator>::Item as Example>::Item, + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:53:9 + | +LL | T = <[(); N] as IntoIterator>::Item::Item, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - T = <[(); N] as IntoIterator>::Item::Item, +LL + T = <<[(); N] as IntoIterator>::Item as Example>::Item, + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:40:9 + | +LL | <[(); N] as IntoIterator>::Item::Item:, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - <[(); N] as IntoIterator>::Item::Item:, +LL + <<[(); N] as IntoIterator>::Item as Example>::Item:, + | + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-issue-163320.rs:58:12 + | +LL | let _: <[(); N] as IntoIterator>::Item::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<[(); N] as IntoIterator>::Item`, you could use the fully-qualified path + | +LL - let _: <[(); N] as IntoIterator>::Item::Item; +LL + let _: <<[(); N] as IntoIterator>::Item as Example>::Item; + | + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/traits/next-solver/assoc-ty-const-generics-original-repro-issue-163320.rs b/tests/ui/traits/next-solver/assoc-ty-const-generics-original-repro-issue-163320.rs new file mode 100644 index 0000000000000..d53e7908adb77 --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-ty-const-generics-original-repro-issue-163320.rs @@ -0,0 +1,27 @@ +// Regression test for the original ICE in issue #163320. +//@ compile-flags: -Znext-solver=globally --crate-type=lib +//@ check-fail + +trait HasStorage { + type Storage; +} + +struct Bits; + +trait TryFromBits { + type Bits; +} + +trait ReadEndian: TryFromBits {} + +struct Zeros; + +impl TryFromBits for Zeros { + type Bits = Bits; +} + +impl ReadEndian for Zeros +where + ::Storage::Bits: Sized, + //~^ ERROR ambiguous associated type +{} diff --git a/tests/ui/traits/next-solver/assoc-ty-const-generics-original-repro-issue-163320.stderr b/tests/ui/traits/next-solver/assoc-ty-const-generics-original-repro-issue-163320.stderr new file mode 100644 index 0000000000000..544f233dfe8a5 --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-ty-const-generics-original-repro-issue-163320.stderr @@ -0,0 +1,15 @@ +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-original-repro-issue-163320.rs:25:5 + | +LL | ::Storage::Bits: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Bits` implemented for `< as TryFromBits>::Bits as HasStorage>::Storage`, you could use the fully-qualified path + | +LL - ::Storage::Bits: Sized, +LL + << as TryFromBits>::Bits as HasStorage>::Storage as Example>::Bits: Sized, + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/traits/next-solver/assoc-ty-const-generics-suggestions-issue-163320.rs b/tests/ui/traits/next-solver/assoc-ty-const-generics-suggestions-issue-163320.rs new file mode 100644 index 0000000000000..ae29f307097cc --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-ty-const-generics-suggestions-issue-163320.rs @@ -0,0 +1,51 @@ +// Suggestions should not need trait solving during either item lowering or +// body type checking. Deep rejection may also admit incompatible impls. + +//@ compile-flags: -Znext-solver=globally +//@ check-fail + +trait Identity { + type Out; +} + +impl Identity for () { + type Out = (u8, u8); +} + +trait Different { + type Out; +} + +impl Different for () { + type Out = (u8, u16); +} + +trait HasItem { + type Item; +} + +impl HasItem for (T, T) { + type Item = (); +} + +type Positive = <<() as Identity>::Out>::Item; +//~^ ERROR ambiguous associated type + +type Negative = <<() as Different>::Out>::Item; +//~^ ERROR ambiguous associated type + +fn body_positive() { + let _: <<() as Identity>::Out>::Item; + //~^ ERROR ambiguous associated type +} + +fn body_negative() { + let _: <<() as Different>::Out>::Item; + //~^ ERROR ambiguous associated type +} + +// Repeated impl parameters can result in false-positive suggestions. +type RepeatedParam = <(u8, u16)>::Item; +//~^ ERROR ambiguous associated type + +fn main() {} diff --git a/tests/ui/traits/next-solver/assoc-ty-const-generics-suggestions-issue-163320.stderr b/tests/ui/traits/next-solver/assoc-ty-const-generics-suggestions-issue-163320.stderr new file mode 100644 index 0000000000000..4d45070d8192a --- /dev/null +++ b/tests/ui/traits/next-solver/assoc-ty-const-generics-suggestions-issue-163320.stderr @@ -0,0 +1,62 @@ +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-suggestions-issue-163320.rs:31:17 + | +LL | type Positive = <<() as Identity>::Out>::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<() as Identity>::Out`, you could use the fully-qualified path + | +LL | type Positive = <<() as Identity>::Out as Example>::Item; + | ++++++++++ + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-suggestions-issue-163320.rs:34:17 + | +LL | type Negative = <<() as Different>::Out>::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<() as Different>::Out`, you could use the fully-qualified path + | +LL | type Negative = <<() as Different>::Out as Example>::Item; + | ++++++++++ + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-suggestions-issue-163320.rs:48:22 + | +LL | type RepeatedParam = <(u8, u16)>::Item; + | ^^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | type RepeatedParam = <(u8, u16) as HasItem>::Item; + | ++++++++++ +LL | type RepeatedParam = <(u8, u16) as IntoAsyncIterator>::Item; + | ++++++++++++++++++++ +LL | type RepeatedParam = <(u8, u16) as IntoIterator>::Item; + | +++++++++++++++ + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-suggestions-issue-163320.rs:38:12 + | +LL | let _: <<() as Identity>::Out>::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<() as Identity>::Out`, you could use the fully-qualified path + | +LL | let _: <<() as Identity>::Out as Example>::Item; + | ++++++++++ + +error[E0223]: ambiguous associated type + --> $DIR/assoc-ty-const-generics-suggestions-issue-163320.rs:43:12 + | +LL | let _: <<() as Different>::Out>::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Item` implemented for `<() as Different>::Out`, you could use the fully-qualified path + | +LL | let _: <<() as Different>::Out as Example>::Item; + | ++++++++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0223`.