diff --git a/crates/hir-ty/src/infer/opaques.rs b/crates/hir-ty/src/infer/opaques.rs index 2d64f9567b37..2c48f7d38f4d 100644 --- a/crates/hir-ty/src/infer/opaques.rs +++ b/crates/hir-ty/src/infer/opaques.rs @@ -1,13 +1,18 @@ //! Defining opaque types via inference. -use rustc_type_ir::{TypeVisitableExt, fold_regions}; +use std::ops::ControlFlow; + +use rustc_type_ir::{ + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, fold_regions, inherent::IntoKind, +}; use tracing::{debug, instrument}; use crate::{ Span, infer::InferenceContext, next_solver::{ - EarlyBinder, OpaqueTypeKey, SolverDefId, TypingMode, + Const, ConstKind, DbInterner, EarlyBinder, GenericArgKind, GenericArgs, OpaqueTypeKey, + SolverDefId, Ty, TyKind, TypingMode, infer::{opaque_types::OpaqueHiddenType, traits::ObligationCause}, }, }; @@ -63,6 +68,39 @@ impl<'db> UsageKind<'db> { } } +// rejects hidden types with foreign params +struct ForeignParamChecker<'db> { + args: GenericArgs<'db>, +} + +impl<'db> rustc_type_ir::TypeVisitor> for ForeignParamChecker<'db> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if let TyKind::Param(param) = ty.kind() + && !matches!( + self.args.get(param.index as usize).map(|arg| arg.kind()), + Some(GenericArgKind::Type(_)) + ) + { + return ControlFlow::Break(()); + } + ty.super_visit_with(self) + } + + fn visit_const(&mut self, ct: Const<'db>) -> Self::Result { + if let ConstKind::Param(param) = ct.kind() + && !matches!( + self.args.get(param.index as usize).map(|arg| arg.kind()), + Some(GenericArgKind::Const(_)) + ) + { + return ControlFlow::Break(()); + } + ct.super_visit_with(self) + } +} + impl<'db> InferenceContext<'db> { fn compute_definition_site_hidden_types( &mut self, @@ -115,7 +153,6 @@ impl<'db> InferenceContext<'db> { } self.result.type_of_opaque.insert(def_id, ty.ty.store()); - continue; } @@ -146,6 +183,16 @@ impl<'db> InferenceContext<'db> { }; let hidden_type = fold_regions(self.interner(), hidden_type, |_, _| self.types.regions.erased); + + // skip uses with foreign params + if hidden_type + .ty + .visit_with(&mut ForeignParamChecker { args: opaque_type_key.args }) + .is_break() + { + return UsageKind::NonDefiningUse(opaque_type_key, hidden_type); + } + UsageKind::HasDefiningUse(hidden_type) } } diff --git a/crates/hir-ty/src/tests/opaque_types.rs b/crates/hir-ty/src/tests/opaque_types.rs index 21d830ed51e3..3aee691ef213 100644 --- a/crates/hir-ty/src/tests/opaque_types.rs +++ b/crates/hir-ty/src/tests/opaque_types.rs @@ -32,6 +32,87 @@ fn test() { ); } +#[test] +fn regression_23125_atpit_with_method_generics() { + check_no_mismatches( + r#" +trait Foo { + type Item; +} +struct S; +struct S2; +impl Foo for S2 { + type Item = impl Sized; + fn foo(_: T) -> Self::Item { + S:: + } +} +"#, + ); +} + +// added multi-method non-defining test +#[test] +fn regression_23125_atpit_method_local_generic_non_defining_use() { + check_no_mismatches( + r#" +trait Foo { + type Item; +} +struct S; +struct S2; +impl Foo for S2 { + type Item = impl Sized; + fn foo(_: U) -> Self::Item { + S:: + } + fn bar() -> Self::Item { + S::<()> + } +} +"#, + ); +} + +#[test] +fn regression_23125_atpit_with_method_generics_impl_generics() { + check_no_mismatches( + r#" +trait Foo { + type Item; +} +struct S; +struct S2(T); +impl Foo for S2 { + type Item = impl Sized; + fn foo(_: U) -> Self::Item { + S:: + } +} +"#, + ); +} + +// added impl-generic no-mismatch test +#[test] +fn regression_23125_atpit_impl_generics_are_defining_use() { + check_no_mismatches( + r#" +trait Foo { + type Item; +} +struct S; +struct S2(T); +impl Foo for S2 { + type Item = impl Sized; + fn foo() -> Self::Item { + S:: + } +} +"#, + ); +} + #[test] fn associated_type_impl_traits_complex() { check_types( @@ -79,6 +160,29 @@ fn test() { ); } +#[test] +fn rpit_with_fn_generics_is_defining_use() { + check_infer( + r#" +trait Foo {} +struct S; +impl Foo for S {} +struct Wrap(T); +impl Foo for Wrap {} + +fn foo() -> impl Foo { + Wrap(T) +} +"#, + expect![[r#" + 112..127 '{ Wrap(T) }': Wrap<{unknown}> + 118..122 'Wrap': fn Wrap<{unknown}>({unknown}) -> Wrap<{unknown}> + 118..125 'Wrap(T)': Wrap<{unknown}> + 123..124 'T': {unknown} + "#]], + ); +} + #[test] fn associated_type_with_impl_trait_in_tuple() { check_no_mismatches(