diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index b7253957edc..9e78e6acba5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -735,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() && let Some(def_id) = def_id.as_local() - && self.opaque_type_origin(def_id, self.param_env).is_some() { + && self.opaque_type_origin(def_id).is_some() { return None; } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index e9c3726f8c3..421eb807a14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -1,10 +1,9 @@ -use crate::infer::opaque_types::may_define_impl_trait_in_assoc_ty_modulo_sig; - use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; use rustc_hir as hir; -use rustc_middle::traits::ObligationCauseCode::{self, MiscObligation}; +use rustc_hir::def::DefKind; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::Printer; use rustc_middle::{ @@ -258,9 +257,9 @@ impl Trait for X { ); } } - (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if matches!(cause.code(), MiscObligation) => { - if let Some(def_id) = alias.def_id.as_local() { - if may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, body_owner_def_id.expect_local(), def_id).is_some() { + (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => { + if tcx.is_type_alias_impl_trait(alias.def_id) { + if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { diag.span_note(tcx.def_span(body_owner_def_id), "\ this item must have the opaque type in its signature \ in order to be able to register hidden types"); diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 0b6f51652fd..545310ad351 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -3,10 +3,9 @@ use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; -use hir::def::DefKind; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_middle::traits::ObligationCause; @@ -54,9 +53,7 @@ impl<'tcx> InferCtxt<'tcx> { } let mut obligations = vec![]; let replace_opaque_type = |def_id: DefId| { - def_id - .as_local() - .map_or(false, |def_id| self.opaque_type_origin(def_id, param_env).is_some()) + def_id.as_local().map_or(false, |def_id| self.opaque_type_origin(def_id).is_some()) }; let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx, @@ -141,7 +138,7 @@ impl<'tcx> InferCtxt<'tcx> { // let x = || foo(); // returns the Opaque assoc with `foo` // } // ``` - self.opaque_type_origin(def_id, param_env)? + self.opaque_type_origin(def_id)? } DefiningAnchor::Bubble => self.opaque_type_origin_unchecked(def_id), DefiningAnchor::Error => return None, @@ -152,9 +149,8 @@ impl<'tcx> InferCtxt<'tcx> { // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias { .. }) = b_def_id - .as_local() - .and_then(|b_def_id| self.opaque_type_origin(b_def_id, param_env)) + if let Some(OpaqueTyOrigin::TyAlias { .. }) = + b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id)) { self.tcx.sess.emit_err(OpaqueHiddenTypeDiag { span: cause.span, @@ -370,12 +366,8 @@ impl<'tcx> InferCtxt<'tcx> { /// Returns the origin of the opaque type `def_id` if we're currently /// in its defining scope. - #[instrument(skip(self, param_env), level = "trace", ret)] - pub fn opaque_type_origin( - &self, - def_id: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - ) -> Option { + #[instrument(skip(self), level = "trace", ret)] + pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option { let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = match self.defining_use_anchor { DefiningAnchor::Bubble | DefiningAnchor::Error => return None, @@ -391,7 +383,7 @@ impl<'tcx> InferCtxt<'tcx> { // Named `type Foo = impl Bar;` hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { if in_assoc_ty { - may_define_impl_trait_in_assoc_ty(self.tcx, parent_def_id, def_id, param_env) + self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id) } else { may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) } @@ -654,105 +646,3 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi ); res } - -#[derive(Debug, TypeVisitable, Clone)] -/// Helper datastructure containing the signature -/// that the opaque type extraction logic uses for determining -/// whether an opaque type may have its hidden types registered -/// by an item. -enum FnSigOrTy<'tcx> { - FnSig(ty::PolyFnSig<'tcx>), - Ty(Ty<'tcx>), -} - -/// Checks that the item may register hidden types for the -/// opaque type, if the opaque type shows up in its signature. -#[instrument(level = "debug", skip(tcx), ret)] -pub fn may_define_impl_trait_in_assoc_ty_modulo_sig<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - opaque_def_id: LocalDefId, -) -> Option>> { - let sig = match tcx.def_kind(def_id) { - DefKind::AssocFn => FnSigOrTy::FnSig(tcx.fn_sig(def_id).subst_identity()), - DefKind::AssocConst | DefKind::AssocTy => { - FnSigOrTy::Ty(tcx.type_of(def_id).subst_identity()) - } - _ => return None, - }; - let impl_id = tcx.local_parent(def_id); - trace!(?impl_id); - let mut assoc_id = opaque_def_id; - // Peel nested opaque types. - while let DefKind::OpaqueTy = tcx.def_kind(assoc_id) { - trace!(?assoc_id); - assoc_id = tcx.local_parent(assoc_id); - } - trace!(?assoc_id); - if !matches!(tcx.def_kind(assoc_id), DefKind::AssocTy) { - tcx.sess - .delay_span_bug(tcx.def_span(opaque_def_id), format!("{:?}", tcx.def_kind(assoc_id))); - } - let assoc_impl_id = tcx.local_parent(assoc_id); - trace!(?assoc_impl_id); - - if impl_id != assoc_impl_id { - return None; - } - - Some(sig) -} - -#[instrument(level = "debug", skip(tcx, param_env), ret)] -fn may_define_impl_trait_in_assoc_ty<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - opaque_def_id: LocalDefId, - param_env: ty::ParamEnv<'tcx>, -) -> bool { - let Some(sig) = may_define_impl_trait_in_assoc_ty_modulo_sig(tcx, def_id, opaque_def_id) else { - return false; - }; - - struct Visitor<'tcx> { - opaque_def_id: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - tcx: TyCtxt<'tcx>, - seen: FxHashSet, - } - - impl<'tcx> TypeVisitor> for Visitor<'tcx> { - type BreakTy = (); - #[instrument(level = "trace", skip(self), ret)] - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> { - // FIXME(oli-obk): We should be checking if the associated type - // is mentioned instead of normalizing to find the opaque type. - // But that requires a way to figure out that a projection refers - // to a specific opaque type. That is probably doable by checking for - // `Self` as the `substs[0]`. - let normalized_ty = self.tcx.normalize_erasing_regions(self.param_env, ty); - if let ty::Alias(ty::Opaque, alias) = normalized_ty.kind() { - if let Some(def_id) = alias.def_id.as_local() { - trace!(?alias.def_id); - if def_id == self.opaque_def_id { - return ControlFlow::Break(()); - } - - if self.seen.insert(def_id) { - // Look into nested obligations like `impl Trait`. - for (pred, _) in self - .tcx - .explicit_item_bounds(alias.def_id) - .subst_iter_copied(self.tcx, alias.substs) - { - pred.visit_with(self)?; - } - } - } - } - normalized_ty.super_visit_with(self) - } - } - sig.visit_with(&mut Visitor { opaque_def_id, param_env, tcx, seen: Default::default() }) - .is_break() -} diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 28a9c1eef1a..b45f7caaabe 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -172,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> { type Result = [u8; size_of::>>()]; } +impl EraseType for ty::Binder<'_, &'_ ty::List>> { + type Result = [u8; size_of::>>>()]; +} + impl EraseType for (&'_ T0, &'_ T1) { type Result = [u8; size_of::<(&'static (), &'static ())>()]; } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8d0737e1eee..31929e4f4f6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1265,7 +1265,7 @@ impl<'tcx> AliasTy<'tcx> { /// Extracts the underlying trait reference and own substs from this projection. /// For example, if this is a projection of `::Item<'a>`, - /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs + /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own substs pub fn trait_ref_and_own_substs( self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 97e1f69057e..9bab693156b 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -36,7 +36,12 @@ pub struct Discr<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum CheckRegions { No, + /// Only permit early bound regions. This is useful for Adts which + /// can never have late bound regions. OnlyEarlyBound, + /// Permit both late bound and early bound regions. Use this for functions, + /// which frequently have late bound regions. + Bound, } #[derive(Copy, Clone, Debug)] @@ -471,15 +476,21 @@ impl<'tcx> TyCtxt<'tcx> { ignore_regions: CheckRegions, ) -> Result<(), NotUniqueParam<'tcx>> { let mut seen = GrowableBitSet::default(); + let mut seen_late = FxHashSet::default(); for arg in substs { match arg.unpack() { GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) { - (CheckRegions::OnlyEarlyBound, ty::ReEarlyBound(p)) => { + (CheckRegions::Bound, ty::ReLateBound(di, reg)) => { + if !seen_late.insert((di, reg)) { + return Err(NotUniqueParam::DuplicateParam(lt.into())); + } + } + (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, ty::ReEarlyBound(p)) => { if !seen.insert(p.index) { return Err(NotUniqueParam::DuplicateParam(lt.into())); } } - (CheckRegions::OnlyEarlyBound, _) => { + (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => { return Err(NotUniqueParam::NotParam(lt.into())); } (CheckRegions::No, _) => {} diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index 15a14112f4a..5bc3e3c00c9 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -55,3 +55,11 @@ ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` + +ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope + .label = generic argument `{$arg}` used twice + .note = for this opaque type + +ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope + .label = argument `{$arg}` is not a generic parameter + .note = for this opaque type diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 3d3fc50e6e5..553bf40ef3a 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ty_utils use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; #[derive(Diagnostic)] @@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> { pub ty: Ty<'tcx>, pub e_ty: Ty<'tcx>, } + +#[derive(Diagnostic)] +#[diag(ty_utils_impl_trait_duplicate_arg)] +pub struct DuplicateArg<'tcx> { + pub arg: GenericArg<'tcx>, + #[primary_span] + #[label] + pub span: Span, + #[note] + pub opaque_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ty_utils_impl_trait_not_param)] +pub struct NotParam<'tcx> { + pub arg: GenericArg<'tcx>, + #[primary_span] + #[label] + pub span: Span, + #[note] + pub opaque_span: Span, +} diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index cdb8e4a439d..25ebb333bf7 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -1,46 +1,165 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::ErrorGuaranteed; use rustc_hir::{def::DefKind, def_id::LocalDefId}; -use rustc_middle::ty::util::CheckRegions; +use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_span::Span; use rustc_type_ir::AliasKind; use std::ops::ControlFlow; +use crate::errors::{DuplicateArg, NotParam}; + struct OpaqueTypeCollector<'tcx> { tcx: TyCtxt<'tcx>, opaques: Vec, + /// The `DefId` of the item which we are collecting opaque types for. + item: LocalDefId, + + /// Avoid infinite recursion due to recursive declarations. + seen: FxHashSet, +} + +impl<'tcx> OpaqueTypeCollector<'tcx> { + fn collect( + tcx: TyCtxt<'tcx>, + item: LocalDefId, + val: ty::Binder<'tcx, impl TypeVisitable>>, + ) -> Vec { + let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() }; + val.skip_binder().visit_with(&mut collector); + collector.opaques + } + + fn span(&self) -> Span { + self.tcx.def_span(self.item) + } + + fn parent(&self) -> Option { + match self.tcx.def_kind(self.item) { + DefKind::Fn => None, + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + Some(self.tcx.local_parent(self.item)) + } + other => span_bug!( + self.tcx.def_span(self.item), + "unhandled item with opaque types: {other:?}" + ), + } + } } impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + type BreakTy = ErrorGuaranteed; + + #[instrument(skip(self), ret, level = "trace")] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { - ty::Alias(AliasKind::Opaque, alias_ty) => { - if let Some(def_id) = alias_ty.def_id.as_local() { - if self - .tcx - .uses_unique_generic_params(alias_ty.substs, CheckRegions::OnlyEarlyBound) - .is_ok() - { - self.opaques.push(def_id); - return ControlFlow::Continue(()); - } else { - warn!(?t, "opaque types with non-unique params in sig: {t:?}"); + ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => { + if !self.seen.insert(alias_ty.def_id.expect_local()) { + return ControlFlow::Continue(()); + } + match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) { + Ok(()) => { + // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not + // supported at all, so this is sound to do, but once we want to support them, you'll + // start seeing the error below. + + self.opaques.push(alias_ty.def_id.expect_local()); + + // Collect opaque types nested within the associated type bounds of this opaque type. + for (pred, _span) in self + .tcx + .explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(self.tcx, alias_ty.substs) + { + trace!(?pred); + pred.visit_with(self)?; + } + + ControlFlow::Continue(()) + } + Err(NotUniqueParam::NotParam(arg)) => { + let err = self.tcx.sess.emit_err(NotParam { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + ControlFlow::Break(err) + } + Err(NotUniqueParam::DuplicateParam(arg)) => { + let err = self.tcx.sess.emit_err(DuplicateArg { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + ControlFlow::Break(err) } } } - _ => {} + ty::Alias(AliasKind::Projection, alias_ty) => { + if let Some(parent) = self.parent() { + trace!(?alias_ty); + let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx); + + trace!(?trait_ref, ?own_substs); + // This avoids having to do normalization of `Self::AssocTy` by only + // supporting the case of a method defining opaque types from assoc types + // in the same impl block. + if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() { + for assoc in self.tcx.associated_items(parent).in_definition_order() { + trace!(?assoc); + if assoc.trait_item_def_id == Some(alias_ty.def_id) { + // We reconstruct the generic args of the associated type within the impl + // from the impl's generics and the generic args passed to the type via the + // projection. + let substs = ty::InternalSubsts::identity_for_item( + self.tcx, + parent.to_def_id(), + ); + trace!(?substs); + let substs: Vec<_> = + substs.iter().chain(own_substs.iter().copied()).collect(); + trace!(?substs); + // Find opaque types in this associated type. + return self + .tcx + .type_of(assoc.def_id) + .subst(self.tcx, &substs) + .visit_with(self); + } + } + } + } + t.super_visit_with(self) + } + _ => t.super_visit_with(self), } - t.super_visit_with(self) } } fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] { - // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT. - match tcx.def_kind(item) { - DefKind::Fn | DefKind::AssocFn => { - let sig = tcx.fn_sig(item).subst_identity(); - let mut collector = OpaqueTypeCollector { tcx, opaques: Vec::new() }; - sig.visit_with(&mut collector); - tcx.arena.alloc_from_iter(collector.opaques) + let kind = tcx.def_kind(item); + trace!(?kind); + // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types. + match kind { + // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` + DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + let defined_opaques = match kind { + DefKind::Fn => { + OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + } + DefKind::AssocFn => { + OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + } + DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect( + tcx, + item, + ty::Binder::dummy(tcx.type_of(item).subst_identity()), + ), + _ => unreachable!(), + }; + tcx.arena.alloc_from_iter(defined_opaques) } DefKind::Mod | DefKind::Struct @@ -51,13 +170,11 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ | DefKind::TyAlias | DefKind::ForeignTy | DefKind::TraitAlias - | DefKind::AssocTy | DefKind::TyParam | DefKind::Const | DefKind::ConstParam | DefKind::Static(_) | DefKind::Ctor(_, _) - | DefKind::AssocConst | DefKind::Macro(_) | DefKind::ExternCrate | DefKind::Use diff --git a/tests/ui/generic-associated-types/issue-88595.rs b/tests/ui/generic-associated-types/issue-88595.rs index 5a40a612972..7de906e7ef3 100644 --- a/tests/ui/generic-associated-types/issue-88595.rs +++ b/tests/ui/generic-associated-types/issue-88595.rs @@ -19,4 +19,5 @@ impl<'a> A<'a> for C { type B<'b> = impl Clone; fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope + //~^ ERROR: mismatched types } diff --git a/tests/ui/generic-associated-types/issue-88595.stderr b/tests/ui/generic-associated-types/issue-88595.stderr index 79d3479af8c..d6caed85459 100644 --- a/tests/ui/generic-associated-types/issue-88595.stderr +++ b/tests/ui/generic-associated-types/issue-88595.stderr @@ -1,16 +1,34 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-88595.rs:21:35 + --> $DIR/issue-88595.rs:21:5 | LL | fn a(&'a self) -> Self::B<'a> {} - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ generic argument `'a` used twice | -note: lifetime used multiple times - --> $DIR/issue-88595.rs:18:6 +note: for this opaque type + --> $DIR/issue-88595.rs:19:18 | -LL | impl<'a> A<'a> for C { - | ^^ LL | type B<'b> = impl Clone; - | ^^ + | ^^^^^^^^^^ -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/issue-88595.rs:21:23 + | +LL | type B<'b> = impl Clone; + | ---------- the expected opaque type +LL | +LL | fn a(&'a self) -> Self::B<'a> {} + | - ^^^^^^^^^^^ expected opaque type, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected opaque type `>::B<'a>` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/issue-88595.rs:21:5 + | +LL | fn a(&'a self) -> Self::B<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.rs b/tests/ui/impl-trait/in-assoc-type-unconstrained.rs new file mode 100644 index 00000000000..c395b4195a0 --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.rs @@ -0,0 +1,27 @@ +#![feature(impl_trait_in_assoc_type)] + +mod compare_ty { + trait Trait { + type Ty: IntoIterator; + } + impl Trait for () { + type Ty = Option; + //~^ ERROR: unconstrained opaque type + //~| ERROR: type mismatch resolving `::Ty::{opaque#0}> as IntoIterator>::Item == ()` + } +} + +mod compare_method { + trait Trait { + type Ty; + fn method() -> Self::Ty; + } + impl Trait for () { + type Ty = impl Sized; + //~^ ERROR: unconstrained opaque type + fn method() -> () {} + //~^ ERROR: method `method` has an incompatible type for trait + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr new file mode 100644 index 00000000000..1097cd0f452 --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr @@ -0,0 +1,59 @@ +error[E0271]: type mismatch resolving `::Ty::{opaque#0}> as IntoIterator>::Item == ()` + --> $DIR/in-assoc-type-unconstrained.rs:8:19 + | +LL | type Ty = Option; + | ^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type + | + = note: expected unit type `()` + found opaque type `<() as compare_ty::Trait>::Ty::{opaque#0}` +note: required by a bound in `compare_ty::Trait::Ty` + --> $DIR/in-assoc-type-unconstrained.rs:5:31 + | +LL | type Ty: IntoIterator; + | ^^^^^^^^^ required by this bound in `Trait::Ty` + +error: unconstrained opaque type + --> $DIR/in-assoc-type-unconstrained.rs:8:26 + | +LL | type Ty = Option; + | ^^^^^^^^^^ + | + = note: `Ty` must be used in combination with a concrete type within the same impl + +error[E0053]: method `method` has an incompatible type for trait + --> $DIR/in-assoc-type-unconstrained.rs:22:24 + | +LL | type Ty = impl Sized; + | ---------- the expected opaque type +LL | +LL | fn method() -> () {} + | ^^ + | | + | expected opaque type, found `()` + | help: change the output type to match the trait: `<() as compare_method::Trait>::Ty` + | +note: type in trait + --> $DIR/in-assoc-type-unconstrained.rs:17:24 + | +LL | fn method() -> Self::Ty; + | ^^^^^^^^ + = note: expected signature `fn() -> <() as compare_method::Trait>::Ty` + found signature `fn()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/in-assoc-type-unconstrained.rs:22:9 + | +LL | fn method() -> () {} + | ^^^^^^^^^^^^^^^^^ + +error: unconstrained opaque type + --> $DIR/in-assoc-type-unconstrained.rs:20:19 + | +LL | type Ty = impl Sized; + | ^^^^^^^^^^ + | + = note: `Ty` must be used in combination with a concrete type within the same impl + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0053, E0271. +For more information about an error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-assoc-type.rs b/tests/ui/impl-trait/in-assoc-type.rs new file mode 100644 index 00000000000..36c54bdd6de --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type.rs @@ -0,0 +1,21 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Bar; + fn foo(&self) -> >::Bar + where + Self: Foo<()>; +} + +impl Foo<()> for () { + type Bar = impl std::fmt::Debug; + fn foo(&self) -> Self::Bar {} +} + +impl Foo for () { + type Bar = u32; + fn foo(&self) -> >::Bar {} + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-assoc-type.stderr b/tests/ui/impl-trait/in-assoc-type.stderr new file mode 100644 index 00000000000..f0a272dc2d5 --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/in-assoc-type.rs:17:22 + | +LL | type Bar = impl std::fmt::Debug; + | -------------------- the expected opaque type +... +LL | fn foo(&self) -> >::Bar {} + | --- ^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected opaque type `<() as Foo<()>>::Bar` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/in-assoc-type.rs:17:5 + | +LL | fn foo(&self) -> >::Bar {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index f7aff419544..fe62a8f3288 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -43,6 +43,11 @@ LL | fn eq(&self, _other: &(Bar, i32)) -> bool { | = note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _` found signature `fn(&b::Bar, &(b::Bar, i32)) -> _` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:9 + | +LL | fn eq(&self, _other: &(Bar, i32)) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs index 21c1d8bcc98..58eaa9c2c42 100644 --- a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs @@ -12,7 +12,9 @@ impl<'a> Trait for &'a () { type Opaque1 = impl Sized; type Opaque2 = impl Sized + 'a; fn constrain(self) -> (Self::Opaque1, Self::Opaque2) { - ((), self) + let a: Self::Opaque1 = (); + let b: Self::Opaque2 = self; + (a, b) } }