diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 11ad5b49df2..4f01e0a24a5 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -63,6 +63,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), + ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"), ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"), ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"), diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs new file mode 100644 index 00000000000..05a3ab63d5c --- /dev/null +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -0,0 +1,124 @@ +use rustc_ast::TraitObjectSyntax; +use rustc_errors::{Diagnostic, StashKey}; +use rustc_hir as hir; +use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; +use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; + +use super::AstConv; + +impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { + /// Make sure that we are in the condition to suggest the blanket implementation. + pub(super) fn maybe_lint_blanket_trait_impl( + &self, + self_ty: &hir::Ty<'_>, + diag: &mut Diagnostic, + ) { + let tcx = self.tcx(); + let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; + if let hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Impl(hir::Impl { + self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, .. + }), + .. + }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id + { + if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { + return; + } + let of_trait_span = of_trait_ref.path.span; + // make sure that we are not calling unwrap to abort during the compilation + let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; }; + let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; }; + // check if the trait has generics, to make a correct suggestion + let param_name = generics.params.next_type_param_name(None); + + let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() { + (span, format!(", {}: {}", param_name, impl_trait_name)) + } else { + (generics.span, format!("<{}: {}>", param_name, impl_trait_name)) + }; + diag.multipart_suggestion( + format!("alternatively use a blanket \ + implementation to implement `{of_trait_name}` for \ + all types that also implement `{impl_trait_name}`"), + vec![ + (self_ty.span, param_name), + add_generic_sugg, + ], + Applicability::MaybeIncorrect, + ); + } + } + + pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { + let tcx = self.tcx(); + if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = + self_ty.kind + { + let needs_bracket = in_path + && !tcx + .sess + .source_map() + .span_to_prev_source(self_ty.span) + .ok() + .is_some_and(|s| s.trim_end().ends_with('<')); + + let is_global = poly_trait_ref.trait_ref.path.is_global(); + + let mut sugg = Vec::from_iter([( + self_ty.span.shrink_to_lo(), + format!( + "{}dyn {}", + if needs_bracket { "<" } else { "" }, + if is_global { "(" } else { "" }, + ), + )]); + + if is_global || needs_bracket { + sugg.push(( + self_ty.span.shrink_to_hi(), + format!( + "{}{}", + if is_global { ")" } else { "" }, + if needs_bracket { ">" } else { "" }, + ), + )); + } + + if self_ty.span.edition().rust_2021() { + let msg = "trait objects must include the `dyn` keyword"; + let label = "add `dyn` keyword before this trait"; + let mut diag = + rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg); + if self_ty.span.can_be_used_for_suggestions() { + diag.multipart_suggestion_verbose( + label, + sugg, + Applicability::MachineApplicable, + ); + } + // check if the impl trait that we are considering is a impl of a local trait + self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); + diag.stash(self_ty.span, StashKey::TraitMissingMethod); + } else { + let msg = "trait objects without an explicit `dyn` are deprecated"; + tcx.struct_span_lint_hir( + BARE_TRAIT_OBJECTS, + self_ty.hir_id, + self_ty.span, + msg, + |lint| { + lint.multipart_suggestion_verbose( + "use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + self.maybe_lint_blanket_trait_impl(&self_ty, lint); + lint + }, + ); + } + } + } +} diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 1037a49acdf..221c7ce4f6f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -4,6 +4,7 @@ mod errors; pub mod generics; +mod lint; use crate::astconv::errors::prohibit_assoc_ty_binding; use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args}; @@ -19,7 +20,7 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, - MultiSpan, StashKey, + MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -33,14 +34,12 @@ use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{DynKind, ToPredicate}; -use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; +use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; -use rustc_trait_selection::traits::error_reporting::{ - report_object_safety_error, suggestions::NextTypeParamName, -}; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{ self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt, @@ -1458,7 +1457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { let substs = self.ast_path_substs_for_ty(span, did, item_segment); - self.tcx().at(span).type_of(did).subst(self.tcx(), substs) + let ty = self.tcx().at(span).type_of(did); + + if matches!(self.tcx().def_kind(did), DefKind::TyAlias) + && ty.skip_binder().has_opaque_types() + { + // Type aliases referring to types that contain opaque types (but aren't just directly + // referencing a single opaque type) get encoded as a type alias that normalization will + // then actually instantiate the where bounds of. + let alias_ty = self.tcx().mk_alias_ty(did, substs); + self.tcx().mk_alias(ty::Weak, alias_ty) + } else { + ty.subst(self.tcx(), substs) + } } fn conv_object_ty_poly_trait_ref( @@ -3703,115 +3714,4 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } Some(r) } - - /// Make sure that we are in the condition to suggest the blanket implementation. - fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) { - let tcx = self.tcx(); - let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; - if let hir::Node::Item(hir::Item { - kind: - hir::ItemKind::Impl(hir::Impl { - self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, .. - }), - .. - }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id - { - if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { - return; - } - let of_trait_span = of_trait_ref.path.span; - // make sure that we are not calling unwrap to abort during the compilation - let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; }; - let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; }; - // check if the trait has generics, to make a correct suggestion - let param_name = generics.params.next_type_param_name(None); - - let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() { - (span, format!(", {}: {}", param_name, impl_trait_name)) - } else { - (generics.span, format!("<{}: {}>", param_name, impl_trait_name)) - }; - diag.multipart_suggestion( - format!("alternatively use a blanket \ - implementation to implement `{of_trait_name}` for \ - all types that also implement `{impl_trait_name}`"), - vec![ - (self_ty.span, param_name), - add_generic_sugg, - ], - Applicability::MaybeIncorrect, - ); - } - } - - fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { - let tcx = self.tcx(); - if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = - self_ty.kind - { - let needs_bracket = in_path - && !tcx - .sess - .source_map() - .span_to_prev_source(self_ty.span) - .ok() - .is_some_and(|s| s.trim_end().ends_with('<')); - - let is_global = poly_trait_ref.trait_ref.path.is_global(); - - let mut sugg = Vec::from_iter([( - self_ty.span.shrink_to_lo(), - format!( - "{}dyn {}", - if needs_bracket { "<" } else { "" }, - if is_global { "(" } else { "" }, - ), - )]); - - if is_global || needs_bracket { - sugg.push(( - self_ty.span.shrink_to_hi(), - format!( - "{}{}", - if is_global { ")" } else { "" }, - if needs_bracket { ">" } else { "" }, - ), - )); - } - - if self_ty.span.edition().rust_2021() { - let msg = "trait objects must include the `dyn` keyword"; - let label = "add `dyn` keyword before this trait"; - let mut diag = - rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg); - if self_ty.span.can_be_used_for_suggestions() { - diag.multipart_suggestion_verbose( - label, - sugg, - Applicability::MachineApplicable, - ); - } - // check if the impl trait that we are considering is a impl of a local trait - self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); - diag.stash(self_ty.span, StashKey::TraitMissingMethod); - } else { - let msg = "trait objects without an explicit `dyn` are deprecated"; - tcx.struct_span_lint_hir( - BARE_TRAIT_OBJECTS, - self_ty.hir_id, - self_ty.span, - msg, - |lint| { - lint.multipart_suggestion_verbose( - "use `dyn`", - sugg, - Applicability::MachineApplicable, - ); - self.maybe_lint_blanket_trait_impl(&self_ty, lint); - lint - }, - ); - } - } - } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4554d167080..f93f395caed 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -217,10 +217,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { check_item_fn(tcx, def_id, item.ident, item.span, sig.decl); } hir::ItemKind::Static(ty, ..) => { - check_item_type(tcx, def_id, ty.span, false); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); } hir::ItemKind::Const(ty, ..) => { - check_item_type(tcx, def_id, ty.span, false); + check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid); } hir::ItemKind::Struct(_, ast_generics) => { check_type_defn(tcx, item, false); @@ -242,6 +242,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { } // `ForeignItem`s are handled separately. hir::ItemKind::ForeignMod { .. } => {} + hir::ItemKind::TyAlias(hir_ty, ..) => { + if tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() { + // Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);` + check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); + } + } _ => {} } } @@ -258,7 +264,9 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) { hir::ForeignItemKind::Fn(decl, ..) => { check_item_fn(tcx, def_id, item.ident, item.span, decl) } - hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true), + hir::ForeignItemKind::Static(ty, ..) => { + check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) + } hir::ForeignItemKind::Type => (), } } @@ -1100,20 +1108,32 @@ fn check_item_fn( }) } -fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) { +enum UnsizedHandling { + Forbid, + Allow, + AllowIfForeignTail, +} + +fn check_item_type( + tcx: TyCtxt<'_>, + item_id: LocalDefId, + ty_span: Span, + unsized_handling: UnsizedHandling, +) { debug!("check_item_type: {:?}", item_id); enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { let ty = tcx.type_of(item_id).subst_identity(); let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); - let mut forbid_unsized = true; - if allow_foreign_ty { - let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env); - if let ty::Foreign(_) = tail.kind() { - forbid_unsized = false; + let forbid_unsized = match unsized_handling { + UnsizedHandling::Forbid => true, + UnsizedHandling::Allow => false, + UnsizedHandling::AllowIfForeignTail => { + let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env); + !matches!(tail.kind(), ty::Foreign(_)) } - } + }; wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); if forbid_unsized { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 23beacd2a8c..eb299a1ea79 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -200,35 +200,32 @@ fn do_orphan_check_impl<'tcx>( NonlocalImpl::DisallowOther, ), - // trait Id { type This: ?Sized; } - // impl Id for T { - // type This = T; - // } - // impl AutoTrait for ::This {} - ty::Alias(AliasKind::Projection, _) => ( - LocalImpl::Disallow { problematic_kind: "associated type" }, - NonlocalImpl::DisallowOther, - ), - - // ``` - // struct S(T); - // impl S { - // type This = T; - // } - // impl AutoTrait for S::This {} - // ``` - // FIXME(inherent_associated_types): The example code above currently leads to a cycle - ty::Alias(AliasKind::Inherent, _) => ( - LocalImpl::Disallow { problematic_kind: "associated type" }, - NonlocalImpl::DisallowOther, - ), - - // type Opaque = impl Trait; - // impl AutoTrait for Opaque {} - ty::Alias(AliasKind::Opaque, _) => ( - LocalImpl::Disallow { problematic_kind: "opaque type" }, - NonlocalImpl::DisallowOther, - ), + ty::Alias(kind, _) => { + let problematic_kind = match kind { + // trait Id { type This: ?Sized; } + // impl Id for T { + // type This = T; + // } + // impl AutoTrait for ::This {} + AliasKind::Projection => "associated type", + // type Foo = (impl Sized, bool) + // impl AutoTrait for Foo {} + AliasKind::Weak => "type alias", + // type Opaque = impl Trait; + // impl AutoTrait for Opaque {} + AliasKind::Opaque => "opaque type", + // ``` + // struct S(T); + // impl S { + // type This = T; + // } + // impl AutoTrait for S::This {} + // ``` + // FIXME(inherent_associated_types): The example code above currently leads to a cycle + AliasKind::Inherent => "associated type", + }; + (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) + } ty::Bool | ty::Char diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index b92d561fb86..90e8e523ea3 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -122,6 +122,7 @@ pub(super) fn explicit_item_bounds( }; opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } + hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], _ => bug!("item_bounds called on {:?}", def_id), }; ty::EarlyBinder::bind(bounds) diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index e4c6e6e391a..a653a652231 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -128,7 +128,9 @@ fn diagnostic_hir_wf_check<'tcx>( ref item => bug!("Unexpected TraitItem {:?}", item), }, hir::Node::Item(item) => match item.kind { - hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty], + hir::ItemKind::TyAlias(ty, _) + | hir::ItemKind::Static(ty, _, _) + | hir::ItemKind::Const(ty, _) => vec![ty], hir::ItemKind::Impl(impl_) => match &impl_.of_trait { Some(t) => t .path diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 3e4812e7ca9..fc1f90fdc13 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2375,6 +2375,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::AliasKind::Projection | ty::AliasKind::Inherent => { format!("the associated type `{}`", p) } + ty::AliasKind::Weak => format!("the type alias `{}`", p), ty::AliasKind::Opaque => format!("the opaque type `{}`", p), }, }; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 7b05bff5151..f02f3668dc1 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1465,8 +1465,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else { return }; - if let hir::TyKind::OpaqueDef(..) = ty.kind { - // Bounds are respected for `type X = impl Trait` + if cx.tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() { + // Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);` return; } if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index ec9e7c7fdae..9a2d45ccd66 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1255,7 +1255,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } ty::Param(..) - | ty::Alias(ty::Projection | ty::Inherent, ..) + | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Infer(..) | ty::Bound(..) | ty::Error(_) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a6c8d41e925..132b11b29eb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1903,6 +1903,16 @@ rustc_queries! { desc { "normalizing `{}`", goal.value.value } } + /// Do not call this query directly: invoke `normalize` instead. + query normalize_weak_ty( + goal: CanonicalProjectionGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, + NoSolution, + > { + desc { "normalizing `{}`", goal.value.value } + } + /// Do not call this query directly: invoke `normalize` instead. query normalize_inherent_projection_ty( goal: CanonicalProjectionGoal<'tcx> diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index bf3872e81d4..b63e049a520 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -448,6 +448,9 @@ pub enum ObligationCauseCode<'tcx> { /// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy` ConstParam(Ty<'tcx>), + + /// Obligations emitted during the normalization of a weak type alias. + TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId), } /// The 'location' at which we try to perform HIR-based wf checking. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4ee543bbfb6..449129b8418 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2012,6 +2012,7 @@ impl<'tcx> TyCtxt<'tcx> { (ty::Opaque, DefKind::OpaqueTy) | (ty::Projection | ty::Inherent, DefKind::AssocTy) | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) + | (ty::Weak, DefKind::TyAlias) ); self.mk_ty_from_kind(Alias(kind, alias_ty)) } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 66293f19eef..c794c3faded 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -300,6 +300,7 @@ impl<'tcx> Ty<'tcx> { ty::Placeholder(..) => "higher-ranked type".into(), ty::Bound(..) => "bound type variable".into(), ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(), + ty::Alias(ty::Weak, _) => "type alias".into(), ty::Param(_) => "type parameter".into(), ty::Alias(ty::Opaque, ..) => "opaque type".into(), } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index d64875a9f00..9cce9d64d5d 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -178,7 +178,7 @@ impl FlagComputation { &ty::Alias(kind, data) => { self.add_flags(match kind { - ty::Projection => TypeFlags::HAS_TY_PROJECTION, + ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION, ty::Inherent => TypeFlags::HAS_TY_INHERENT, ty::Opaque => TypeFlags::HAS_TY_OPAQUE, }); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6156fdf7eac..f36b8ad8df6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -731,7 +731,7 @@ pub trait PrettyPrinter<'tcx>: ty::Foreign(def_id) => { p!(print_def_path(def_id, &[])); } - ty::Alias(ty::Projection | ty::Inherent, ref data) => { + ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ref data) => { if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get())) && self.tcx().is_impl_trait_in_trait(data.def_id) { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 8bcae3d9ab7..74a3bddf2fa 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -391,13 +391,13 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { /// Relates `a` and `b` structurally, calling the relation for all nested values. /// Any semantic equality, e.g. of projections, and inference variables have to be /// handled by the caller. +#[instrument(level = "trace", skip(relation), ret)] pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { let tcx = relation.tcx(); - debug!("structurally_relate_tys: a={:?} b={:?}", a, b); match (a.kind(), b.kind()) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { // The caller should handle these cases! diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d19a7bcde79..5f2f241bc0d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1231,6 +1231,7 @@ impl<'tcx> AliasTy<'tcx> { DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent, DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection, DefKind::OpaqueTy => ty::Opaque, + DefKind::TyAlias => ty::Weak, kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index a51a1c9a8a4..5ef11acadce 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -242,6 +242,9 @@ where } } } + ty::Alias(ty::Weak, alias) => { + self.def_id_visitor.visit_def_id(alias.def_id, "type alias", &ty); + } ty::Alias(ty::Projection, proj) => { if self.def_id_visitor.skip_assoc_tys() { // Visitors searching for minimal visibility/reachability want to diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0a805e2422d..5dc00e31786 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -483,6 +483,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { } ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"), + ty::Alias(ty::Weak, _) => bug!("symbol_names: unexpected weak projection"), ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"), } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index e6eddf24844..543611daae8 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -510,10 +510,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Alias(ty::Inherent, _) + | ty::Alias(ty::Weak, _) | ty::Error(_) => return, ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - // Excluding IATs here as they don't have meaningful item bounds. + // Excluding IATs and type aliases here as they don't have meaningful item bounds. ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty, }; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 0f3f8f1ac2c..97b86a06c8c 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) - | ty::Alias(ty::Projection | ty::Inherent, ..) + | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index f4c29c837b8..a30a14df80b 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -29,6 +29,7 @@ mod opaques; mod project_goals; mod search_graph; mod trait_goals; +mod weak_types; pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt}; pub use fulfill::FulfillmentCtxt; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 8303bab4c36..e9600968f48 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -57,6 +57,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } DefKind::AnonConst => self.normalize_anon_const(goal), DefKind::OpaqueTy => self.normalize_opaque_type(goal), + DefKind::TyAlias => self.normalize_weak_type(goal), kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)), } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 60cf386a289..279fc1229d4 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -618,7 +618,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) - | ty::Alias(ty::Projection | ty::Inherent, ..) + | ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..) | ty::Placeholder(..) => Some(Err(NoSolution)), ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), diff --git a/compiler/rustc_trait_selection/src/solve/weak_types.rs b/compiler/rustc_trait_selection/src/solve/weak_types.rs new file mode 100644 index 00000000000..b095b54c554 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/weak_types.rs @@ -0,0 +1,19 @@ +use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; +use rustc_middle::ty; + +use super::EvalCtxt; + +impl<'tcx> EvalCtxt<'_, 'tcx> { + pub(super) fn normalize_weak_type( + &mut self, + goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>, + ) -> QueryResult<'tcx> { + let tcx = self.tcx(); + let weak_ty = goal.predicate.projection_ty; + let expected = goal.predicate.term.ty().expect("no such thing as a const alias"); + + let actual = tcx.type_of(weak_ty.def_id).subst(tcx, weak_ty.substs); + self.eq(goal.param_env, expected, actual)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 3193d00e11b..0065c7fc253 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -695,7 +695,9 @@ impl<'tcx> TypeVisitor> for OrphanChecker<'tcx> { | ty::RawPtr(..) | ty::Never | ty::Tuple(..) - | ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty), + | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => { + self.found_non_local_ty(ty) + } ty::Param(..) => self.found_param_ty(ty), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 1bc4599377a..ffbe2888bf8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1824,12 +1824,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Alias(ty::Projection, ..) => Some(12), ty::Alias(ty::Inherent, ..) => Some(13), ty::Alias(ty::Opaque, ..) => Some(14), - ty::Never => Some(15), - ty::Adt(..) => Some(16), - ty::Generator(..) => Some(17), - ty::Foreign(..) => Some(18), - ty::GeneratorWitness(..) => Some(19), - ty::GeneratorWitnessMIR(..) => Some(20), + ty::Alias(ty::Weak, ..) => Some(15), + ty::Never => Some(16), + ty::Adt(..) => Some(17), + ty::Generator(..) => Some(18), + ty::Foreign(..) => Some(19), + ty::GeneratorWitness(..) => Some(20), + ty::GeneratorWitnessMIR(..) => Some(21), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5783383e93e..fcf813e3a39 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3198,6 +3198,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) }); } + ObligationCauseCode::TypeAlias(ref nested, span, def_id) => { + // #74711: avoid a stack overflow + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + body_id, + err, + predicate, + param_env, + nested, + obligated_types, + seen_requirements, + ) + }); + let mut multispan = MultiSpan::from(span); + multispan.push_span_label(span, "required by this bound"); + err.span_note( + multispan, + format!( + "required by a bound on the type alias `{}`", + self.infcx.tcx.item_name(def_id) + ), + ); + } ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index f8d056e321e..ff55eaf13ad 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId; pub use rustc_middle::traits::query::OutlivesBound; -type Bounds<'a, 'tcx: 'a> = impl Iterator> + 'a; +pub type Bounds<'a, 'tcx: 'a> = impl Iterator> + 'a; pub trait InferCtxtExt<'a, 'tcx> { fn implied_outlives_bounds( &self, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0a1e971f268..8466b3fc954 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -31,6 +31,7 @@ use rustc_infer::infer::at::At; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::ImplSourceBuiltinData; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt}; @@ -621,6 +622,30 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx ); normalized_ty } + ty::Weak => { + let infcx = self.selcx.infcx; + self.obligations.extend( + infcx + .tcx + .predicates_of(data.def_id) + .instantiate_own(infcx.tcx, data.substs) + .map(|(mut predicate, span)| { + if data.has_escaping_bound_vars() { + (predicate, ..) = BoundVarReplacer::replace_bound_vars( + infcx, + &mut self.universes, + predicate, + ); + } + let mut cause = self.cause.clone(); + cause.map_code(|code| { + ObligationCauseCode::TypeAlias(code, span, data.def_id) + }); + Obligation::new(infcx.tcx, cause, self.param_env, predicate) + }), + ); + infcx.tcx.type_of(data.def_id).subst(infcx.tcx, data.substs).fold_with(self) + } ty::Inherent if !data.has_escaping_bound_vars() => { // This branch is *mostly* just an optimization: when we don't @@ -1545,7 +1570,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. let bounds = match *obligation.predicate.self_ty().kind() { - // Excluding IATs here as they don't have meaningful item bounds. + // Excluding IATs and type aliases here as they don't have meaningful item bounds. ty::Alias(ty::Projection | ty::Opaque, ref data) => { tcx.item_bounds(data.def_id).subst(tcx, data.substs) } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 8bf934cb78a..2d97a808225 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -257,7 +257,7 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> ty::Opaque => ty.try_super_fold_with(self)?, - ty::Projection | ty::Inherent => { + ty::Projection | ty::Inherent | ty::Weak => { // See note in `rustc_trait_selection::traits::project` let infcx = self.infcx; @@ -282,6 +282,7 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = match kind { ty::Projection => tcx.normalize_projection_ty(c_data), + ty::Weak => tcx.normalize_weak_ty(c_data), ty::Inherent => tcx.normalize_inherent_projection_ty(c_data), _ => unreachable!(), }?; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3c223db5a0b..f2dfa6921f4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -143,7 +143,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { - // Excluding IATs here as they don't have meaningful item bounds. + // Excluding IATs and type aliases here as they don't have meaningful item bounds. ty::Alias(ty::Projection | ty::Opaque, _) => {} ty::Infer(ty::TyVar(_)) => { span_bug!( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 7853af959ad..d2c2cadd617 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -163,7 +163,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { - // Excluding IATs here as they don't have meaningful item bounds. + // Excluding IATs and type aliases here as they don't have meaningful item bounds. ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { (def_id, substs) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4c5a794bc81..e72d3ca97d7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2314,7 +2314,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) - | ty::Alias(ty::Projection | ty::Inherent, ..) + | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("asked to assemble constituent types of unexpected type: {:?}", t); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 086ab32b520..92d899b0f13 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -731,6 +731,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } + ty::Alias(ty::Weak, ty::AliasTy { def_id, substs, .. }) => { + let obligations = self.nominal_obligations(def_id, substs); + self.out.extend(obligations); + } + ty::Dynamic(data, r, _) => { // WfObject // diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e6c6e0f13df..f9a7c8c386a 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -372,6 +372,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { substitution: substs.lower_into(interner), })) } + ty::Alias(ty::Weak, ty::AliasTy { .. }) => unimplemented!(), ty::Alias(ty::Inherent, _) => unimplemented!(), ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index b552ba41acd..83828f177bc 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -10,7 +10,12 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext}; use std::sync::atomic::Ordering; pub(crate) fn provide(p: &mut Providers) { - *p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p }; + *p = Providers { + normalize_projection_ty, + normalize_weak_ty, + normalize_inherent_projection_ty, + ..*p + }; } fn normalize_projection_ty<'tcx>( @@ -43,6 +48,33 @@ fn normalize_projection_ty<'tcx>( ) } +fn normalize_weak_ty<'tcx>( + tcx: TyCtxt<'tcx>, + goal: CanonicalProjectionGoal<'tcx>, +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { + debug!("normalize_provider(goal={:#?})", goal); + + tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed); + tcx.infer_ctxt().enter_canonical_trait_query( + &goal, + |ocx, ParamEnvAnd { param_env, value: goal }| { + let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.substs).map( + |(predicate, span)| { + traits::Obligation::new( + tcx, + ObligationCause::dummy_with_span(span), + param_env, + predicate, + ) + }, + ); + ocx.register_obligations(obligations); + let normalized_ty = tcx.type_of(goal.def_id).subst(tcx, goal.substs); + Ok(NormalizationResult { normalized_ty }) + }, + ) +} + fn normalize_inherent_projection_ty<'tcx>( tcx: TyCtxt<'tcx>, goal: CanonicalProjectionGoal<'tcx>, diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index fa18f921ee4..f621673f1d6 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -36,9 +36,17 @@ pub enum DynKind { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum AliasKind { + /// A projection `::AssocType`. + /// Can get normalized away if monomorphic enough. Projection, Inherent, + /// An opaque type (usually from `impl Trait` in type aliases or function return types) + /// Can only be normalized away in RevealAll mode Opaque, + /// A type alias that actually checks its trait bounds. + /// Currently only used if the type alias references opaque types. + /// Can always be normalized away. + Weak, } /// Defines the kinds of types used by the type system. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0c7950bfd3d..9f698a3b6bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2052,6 +2052,11 @@ pub(crate) fn clean_middle_ty<'tcx>( })) } + ty::Alias(ty::Weak, data) => { + let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs); + clean_middle_ty(bound_ty.rebind(ty), cx, None, None) + } + ty::Param(ref p) => { if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) { ImplTrait(bounds) diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index a1d2147cb49..dbaf6aaa853 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1424,6 +1424,7 @@ fn ty_auto_deref_stability<'tcx>( continue; }, ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty), + ty::Alias(ty::Weak, _) => unreachable!("should have been normalized away above"), ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"), ty::Alias(ty::Projection, _) if ty.has_non_region_param() => { TyPosition::new_deref_stable_for_result(precedence, ty) diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed index d18f9387565..204019130ed 100644 --- a/src/tools/clippy/tests/ui/from_over_into.fixed +++ b/src/tools/clippy/tests/ui/from_over_into.fixed @@ -82,10 +82,4 @@ fn msrv_1_41() { } } -type Opaque = impl Sized; -struct IntoOpaque; -impl Into for IntoOpaque { - fn into(self) -> Opaque {} -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs index de8ff0b06bd..46e02847e30 100644 --- a/src/tools/clippy/tests/ui/from_over_into.rs +++ b/src/tools/clippy/tests/ui/from_over_into.rs @@ -82,10 +82,4 @@ fn msrv_1_41() { } } -type Opaque = impl Sized; -struct IntoOpaque; -impl Into for IntoOpaque { - fn into(self) -> Opaque {} -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs index 3b280b7488a..bd62c655216 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs @@ -32,4 +32,10 @@ impl Into for ContainsVal { } } +type Opaque = impl Sized; +struct IntoOpaque; +impl Into for IntoOpaque { + fn into(self) -> Opaque {} +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr index 251f1d84e74..bb966af4b0f 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr @@ -1,29 +1,12 @@ -error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into_unfixable.rs:11:1 +error[E0658]: `impl Trait` in type aliases is unstable + --> $DIR/from_over_into_unfixable.rs:35:15 | -LL | impl Into for String { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Opaque = impl Sized; + | ^^^^^^^^^^ | - = help: replace the `Into` implementation with `From` - = note: `-D clippy::from-over-into` implied by `-D warnings` + = note: see issue #63063 for more information + = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable -error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into_unfixable.rs:19:1 - | -LL | impl Into for &'static [u8] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: replace the `Into` implementation with `From<&'static [u8]>` - -error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into_unfixable.rs:28:1 - | -LL | impl Into for ContainsVal { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `impl From for Foreign` is allowed by the orphan rules, for more information see - https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence - = help: replace the `Into` implementation with `From` - -error: aborting due to 3 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0658`. diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.rs b/src/tools/clippy/tests/ui/new_ret_no_self.rs index a2a30c8b931..4eff62b85ff 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.rs +++ b/src/tools/clippy/tests/ui/new_ret_no_self.rs @@ -401,25 +401,3 @@ mod issue7344 { } } } - -mod issue10041 { - struct Bomb; - - impl Bomb { - // Hidden default generic parameter. - pub fn new() -> impl PartialOrd { - 0i32 - } - } - - // TAIT with self-referencing bounds - type X = impl std::ops::Add; - - struct Bomb2; - - impl Bomb2 { - pub fn new() -> X { - 0i32 - } - } -} diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.stderr b/src/tools/clippy/tests/ui/new_ret_no_self.stderr index 2eaebfb5cac..2b053b462b1 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.stderr +++ b/src/tools/clippy/tests/ui/new_ret_no_self.stderr @@ -92,21 +92,5 @@ LL | | unimplemented!() LL | | } | |_________^ -error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:410:9 - | -LL | / pub fn new() -> impl PartialOrd { -LL | | 0i32 -LL | | } - | |_________^ - -error: methods called `new` usually return `Self` - --> $DIR/new_ret_no_self.rs:421:9 - | -LL | / pub fn new() -> X { -LL | | 0i32 -LL | | } - | |_________^ - -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs new file mode 100644 index 00000000000..7bc6fec10ba --- /dev/null +++ b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs @@ -0,0 +1,26 @@ +#![feature(type_alias_impl_trait)] +#![warn(clippy::new_ret_no_self)] + +mod issue10041 { + struct Bomb; + + impl Bomb { + // Hidden default generic parameter. + pub fn new() -> impl PartialOrd { + 0i32 + } + } + + // TAIT with self-referencing bounds + type X = impl std::ops::Add; + + struct Bomb2; + + impl Bomb2 { + pub fn new() -> X { + 0i32 + } + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/new_ret_no_self_overflow.stderr b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.stderr new file mode 100644 index 00000000000..babb634fdcd --- /dev/null +++ b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `::Output == issue10041::X` + --> $DIR/new_ret_no_self_overflow.rs:20:25 + | +LL | pub fn new() -> X { + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/nested-return-type2-tait.stderr b/tests/ui/impl-trait/nested-return-type2-tait.stderr index a8eb69cfcb7..4383e8ab3a0 100644 --- a/tests/ui/impl-trait/nested-return-type2-tait.stderr +++ b/tests/ui/impl-trait/nested-return-type2-tait.stderr @@ -8,10 +8,6 @@ LL | fn foo() -> impl Trait { | ^^^^^^^^^^^^^^^^ | = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -help: add this bound - | -LL | type Sendable = impl Send + Duh; - | +++++ warning: 1 warning emitted diff --git a/tests/ui/impl-trait/nested-return-type3-tait.stderr b/tests/ui/impl-trait/nested-return-type3-tait.stderr index 5f58c8dca4a..d32944a0d72 100644 --- a/tests/ui/impl-trait/nested-return-type3-tait.stderr +++ b/tests/ui/impl-trait/nested-return-type3-tait.stderr @@ -8,10 +8,6 @@ LL | fn foo() -> impl Trait { | ^^^^^^^^^^^^^^^^ | = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -help: add this bound - | -LL | type Sendable = impl Send + Duh; - | +++++ warning: 1 warning emitted diff --git a/tests/ui/impl-trait/nested-return-type3-tait2.stderr b/tests/ui/impl-trait/nested-return-type3-tait2.stderr index c07f6ead750..a2eddd11665 100644 --- a/tests/ui/impl-trait/nested-return-type3-tait2.stderr +++ b/tests/ui/impl-trait/nested-return-type3-tait2.stderr @@ -8,10 +8,6 @@ LL | type Traitable = impl Trait; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -help: add this bound - | -LL | type Sendable = impl Send + Duh; - | +++++ warning: 1 warning emitted diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs index af9dfe25bb4..01c933473ea 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs @@ -1,5 +1,7 @@ #![feature(type_alias_impl_trait)] +// check-pass + type Foo = impl PartialEq<(Foo, i32)>; struct Bar; @@ -11,7 +13,6 @@ impl PartialEq<(Foo, i32)> for Bar { } fn foo() -> Foo { - //~^ ERROR can't compare `Bar` with `(Bar, i32)` Bar } diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr deleted file mode 100644 index 7b63a3d0b9f..00000000000 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0277]: can't compare `Bar` with `(Bar, i32)` - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:13:13 - | -LL | fn foo() -> Foo { - | ^^^ no implementation for `Bar == (Bar, i32)` -LL | -LL | Bar - | --- return type was inferred to be `Bar` here - | - = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar` - = help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. 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 fe62a8f3288..bbd60d4398b 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 @@ -20,6 +20,11 @@ LL | fn eq(&self, _other: &(Foo, i32)) -> bool { | = note: expected signature `fn(&a::Bar, &(a::Bar, i32)) -> _` found signature `fn(&a::Bar, &(a::Foo, 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:10:9 + | +LL | fn eq(&self, _other: &(Foo, i32)) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unconstrained opaque type --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16 diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs index ad0a003e879..aab10be2de2 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(type_alias_impl_trait)] type Foo = impl PartialEq<(Foo, i32)>; @@ -13,6 +11,7 @@ impl PartialEq<(Bar, i32)> for Bar { } fn foo() -> Foo { + //~^ ERROR can't compare `Bar` with `(Foo, i32)` Bar } diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.stderr new file mode 100644 index 00000000000..b98b859a99b --- /dev/null +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.stderr @@ -0,0 +1,15 @@ +error[E0277]: can't compare `Bar` with `(Foo, i32)` + --> $DIR/recursive-type-alias-impl-trait-declaration.rs:13:13 + | +LL | fn foo() -> Foo { + | ^^^ no implementation for `Bar == (Foo, i32)` +LL | +LL | Bar + | --- return type was inferred to be `Bar` here + | + = help: the trait `PartialEq<(Foo, i32)>` is not implemented for `Bar` + = help: the trait `PartialEq<(Bar, i32)>` is implemented for `Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lint/lint-ctypes-73249-2.rs b/tests/ui/lint/lint-ctypes-73249-2.rs index 691047c8a40..f30377d6c16 100644 --- a/tests/ui/lint/lint-ctypes-73249-2.rs +++ b/tests/ui/lint/lint-ctypes-73249-2.rs @@ -1,7 +1,7 @@ #![feature(type_alias_impl_trait)] #![deny(improper_ctypes)] -pub trait Baz {} +trait Baz {} impl Baz for () {} @@ -9,7 +9,7 @@ type Qux = impl Baz; fn assign() -> Qux {} -pub trait Foo { +trait Foo { type Assoc: 'static; } @@ -18,12 +18,12 @@ impl Foo for () { } #[repr(transparent)] -pub struct A { +struct A { x: &'static ::Assoc, } extern "C" { - pub fn lint_me() -> A<()>; //~ ERROR: uses type `Qux` + fn lint_me() -> A<()>; //~ ERROR: uses type `Qux` } fn main() {} diff --git a/tests/ui/lint/lint-ctypes-73249-2.stderr b/tests/ui/lint/lint-ctypes-73249-2.stderr index 8073c33dd46..49fa54114b2 100644 --- a/tests/ui/lint/lint-ctypes-73249-2.stderr +++ b/tests/ui/lint/lint-ctypes-73249-2.stderr @@ -1,8 +1,8 @@ error: `extern` block uses type `Qux`, which is not FFI-safe - --> $DIR/lint-ctypes-73249-2.rs:26:25 + --> $DIR/lint-ctypes-73249-2.rs:26:21 | -LL | pub fn lint_me() -> A<()>; - | ^^^^^ not FFI-safe +LL | fn lint_me() -> A<()>; + | ^^^^^ not FFI-safe | = note: opaque types have no C equivalent note: the lint level is defined here diff --git a/tests/ui/lint/lint-ctypes-73251-1.rs b/tests/ui/lint/lint-ctypes-73251-1.rs index 145ba784f7c..fc11f23a104 100644 --- a/tests/ui/lint/lint-ctypes-73251-1.rs +++ b/tests/ui/lint/lint-ctypes-73251-1.rs @@ -1,13 +1,13 @@ #![feature(type_alias_impl_trait)] #![deny(improper_ctypes)] -pub trait Baz {} +trait Baz {} impl Baz for u32 {} type Qux = impl Baz; -pub trait Foo { +trait Foo { type Assoc; } @@ -20,7 +20,7 @@ fn assign() -> Qux { } extern "C" { - pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `Qux` + fn lint_me() -> ::Assoc; //~ ERROR: uses type `Qux` } fn main() {} diff --git a/tests/ui/lint/lint-ctypes-73251-1.stderr b/tests/ui/lint/lint-ctypes-73251-1.stderr index 9f43576ad73..b4eb921b97e 100644 --- a/tests/ui/lint/lint-ctypes-73251-1.stderr +++ b/tests/ui/lint/lint-ctypes-73251-1.stderr @@ -1,8 +1,8 @@ error: `extern` block uses type `Qux`, which is not FFI-safe - --> $DIR/lint-ctypes-73251-1.rs:23:25 + --> $DIR/lint-ctypes-73251-1.rs:23:21 | -LL | pub fn lint_me() -> ::Assoc; - | ^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: opaque types have no C equivalent note: the lint level is defined here diff --git a/tests/ui/lint/lint-ctypes-73251-2.rs b/tests/ui/lint/lint-ctypes-73251-2.rs index df71a945796..fbe0a58f3b5 100644 --- a/tests/ui/lint/lint-ctypes-73251-2.rs +++ b/tests/ui/lint/lint-ctypes-73251-2.rs @@ -33,7 +33,7 @@ fn use_of_b() -> AliasB { } extern "C" { - pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `AliasA` + fn lint_me() -> ::Assoc; //~ ERROR: uses type `AliasA` } fn main() {} diff --git a/tests/ui/lint/lint-ctypes-73251-2.stderr b/tests/ui/lint/lint-ctypes-73251-2.stderr index 0b3de379c19..e44cd45bd30 100644 --- a/tests/ui/lint/lint-ctypes-73251-2.stderr +++ b/tests/ui/lint/lint-ctypes-73251-2.stderr @@ -1,8 +1,8 @@ error: `extern` block uses type `AliasA`, which is not FFI-safe - --> $DIR/lint-ctypes-73251-2.rs:36:25 + --> $DIR/lint-ctypes-73251-2.rs:36:21 | -LL | pub fn lint_me() -> ::Assoc; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe +LL | fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: opaque types have no C equivalent note: the lint level is defined here diff --git a/tests/ui/lint/lint-ctypes-73251.rs b/tests/ui/lint/lint-ctypes-73251.rs index ebc2ca77b67..a00d1a75aec 100644 --- a/tests/ui/lint/lint-ctypes-73251.rs +++ b/tests/ui/lint/lint-ctypes-73251.rs @@ -3,7 +3,7 @@ #![feature(type_alias_impl_trait)] #![deny(improper_ctypes)] -pub trait Foo { +trait Foo { type Assoc; } @@ -16,7 +16,7 @@ type Bar = impl Foo; fn assign() -> Bar {} extern "C" { - pub fn lint_me() -> ::Assoc; + fn lint_me() -> ::Assoc; } fn main() {} diff --git a/tests/ui/lint/opaque-ty-ffi-unsafe.rs b/tests/ui/lint/opaque-ty-ffi-unsafe.rs index b7cc38e99fc..5faeac9ed4c 100644 --- a/tests/ui/lint/opaque-ty-ffi-unsafe.rs +++ b/tests/ui/lint/opaque-ty-ffi-unsafe.rs @@ -3,12 +3,12 @@ type A = impl Fn(); -pub fn ret_closure() -> A { +pub(crate) fn ret_closure() -> A { || {} } extern "C" { - pub fn a(_: A); + pub(crate) fn a(_: A); //~^ ERROR `extern` block uses type `A`, which is not FFI-safe [improper_ctypes] } diff --git a/tests/ui/lint/opaque-ty-ffi-unsafe.stderr b/tests/ui/lint/opaque-ty-ffi-unsafe.stderr index 33aa95854e3..ba9e18bcce5 100644 --- a/tests/ui/lint/opaque-ty-ffi-unsafe.stderr +++ b/tests/ui/lint/opaque-ty-ffi-unsafe.stderr @@ -1,8 +1,8 @@ error: `extern` block uses type `A`, which is not FFI-safe - --> $DIR/opaque-ty-ffi-unsafe.rs:11:17 + --> $DIR/opaque-ty-ffi-unsafe.rs:11:24 | -LL | pub fn a(_: A); - | ^ not FFI-safe +LL | pub(crate) fn a(_: A); + | ^ not FFI-safe | = note: opaque types have no C equivalent note: the lint level is defined here diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage.rs b/tests/ui/type-alias-impl-trait/auto-trait-leakage.rs index a1584581e6c..d9f7c7809b9 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage.rs +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage.rs @@ -4,9 +4,9 @@ #![allow(dead_code)] mod m { - type Foo = impl std::fmt::Debug; + pub(crate) type Foo = impl std::fmt::Debug; - pub fn foo() -> Foo { + pub(crate) fn foo() -> Foo { 22_u32 } } diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked3.rs b/tests/ui/type-alias-impl-trait/bounds-are-checked3.rs new file mode 100644 index 00000000000..5a9e87c0919 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bounds-are-checked3.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +use std::fmt::{Debug, Display}; + +struct Struct(Option); + +// Make sure that, in contrast to type aliases without opaque types, +// we actually do a wf check for the aliased type. +type Foo = (impl Debug, Struct); +//~^ ERROR: `T` doesn't implement `std::fmt::Display` + +fn foo() -> Foo { + (Vec::::new(), Struct(None)) +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr new file mode 100644 index 00000000000..a845cba7716 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr @@ -0,0 +1,20 @@ +error[E0277]: `T` doesn't implement `std::fmt::Display` + --> $DIR/bounds-are-checked3.rs:9:35 + | +LL | type Foo = (impl Debug, Struct); + | ^^^^^^^^^ `T` cannot be formatted with the default formatter + | + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `Struct` + --> $DIR/bounds-are-checked3.rs:5:18 + | +LL | struct Struct(Option); + | ^^^^^^^ required by this bound in `Struct` +help: consider further restricting this bound + | +LL | type Foo = (impl Debug, Struct); + | +++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/bounds.rs b/tests/ui/type-alias-impl-trait/bounds.rs new file mode 100644 index 00000000000..dc05b70c5cc --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bounds.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +// check-pass + +use std::fmt::Debug; + +// No need to report the `type_alias_bounds` lint, as +// the moment an opaque type is mentioned, we actually do check +// type alias bounds. +type Foo = (impl Debug, usize); + +fn foo() -> Foo { + (Vec::::new(), 1234) +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/coherence.stderr b/tests/ui/type-alias-impl-trait/coherence.stderr index 00b0dbbb583..c923eb08ab3 100644 --- a/tests/ui/type-alias-impl-trait/coherence.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl foreign_crate::ForeignTrait for AliasOfForeignType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------- | | | - | | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate + | | `AliasOfForeignType` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/tests/ui/type-alias-impl-trait/defining-use-submodule.rs b/tests/ui/type-alias-impl-trait/defining-use-submodule.rs index 8b51f55715e..4d84b2cbbe9 100644 --- a/tests/ui/type-alias-impl-trait/defining-use-submodule.rs +++ b/tests/ui/type-alias-impl-trait/defining-use-submodule.rs @@ -11,12 +11,12 @@ type Foo = impl std::fmt::Display; type Bar = impl std::fmt::Display; mod foo { - pub fn foo() -> super::Foo { + pub(crate) fn foo() -> super::Foo { "foo" } - pub mod bar { - pub fn bar() -> crate::Bar { + pub(crate) mod bar { + pub(crate) fn bar() -> crate::Bar { 1 } } diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr index c73288329b0..bc9280127ac 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -4,11 +4,11 @@ error[E0277]: the trait bound `T: Trait` is not satisfied LL | fn underconstrain(_: T) -> Underconstrained { | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | -note: required by a bound in `Underconstrained` +note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained.rs:6:26 | LL | type Underconstrained = impl Send; - | ^^^^^ required by this bound in `Underconstrained` + | ^^^^^ required by this bound help: consider restricting type parameter `T` | LL | fn underconstrain(_: T) -> Underconstrained { diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr index d77d978aa44..fdc9ec090db 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -4,11 +4,11 @@ error[E0277]: `U` doesn't implement `Debug` LL | fn underconstrained(_: U) -> Underconstrained { | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | -note: required by a bound in `Underconstrained` +note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 | LL | type Underconstrained = impl Send; - | ^^^^^^^^^^^^^^^ required by this bound in `Underconstrained` + | ^^^^^^^^^^^^^^^ required by this bound help: consider restricting type parameter `U` | LL | fn underconstrained(_: U) -> Underconstrained { @@ -20,11 +20,11 @@ error[E0277]: `V` doesn't implement `Debug` LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | -note: required by a bound in `Underconstrained2` +note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:13:27 | LL | type Underconstrained2 = impl Send; - | ^^^^^^^^^^^^^^^ required by this bound in `Underconstrained2` + | ^^^^^^^^^^^^^^^ required by this bound help: consider restricting type parameter `V` | LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { diff --git a/tests/ui/type-alias-impl-trait/impl_for_weak_alias.rs b/tests/ui/type-alias-impl-trait/impl_for_weak_alias.rs new file mode 100644 index 00000000000..00d1a1a226d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl_for_weak_alias.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] +#![feature(auto_traits)] + +type Alias = (impl Sized, u8); + +auto trait Trait {} +impl Trait for Alias {} +//~^ ERROR traits with a default impl, like `Trait`, cannot be implemented for type alias `Alias` + +fn _def() -> Alias { + (42, 42) +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/impl_for_weak_alias.stderr b/tests/ui/type-alias-impl-trait/impl_for_weak_alias.stderr new file mode 100644 index 00000000000..c312ee7dece --- /dev/null +++ b/tests/ui/type-alias-impl-trait/impl_for_weak_alias.stderr @@ -0,0 +1,11 @@ +error[E0321]: traits with a default impl, like `Trait`, cannot be implemented for type alias `Alias` + --> $DIR/impl_for_weak_alias.rs:7:1 + | +LL | impl Trait for Alias {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: a trait object implements `Trait` if and only if `Trait` is one of the trait object's trait bounds + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0321`. diff --git a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs index 4a11bb5020e..b89c3e4590f 100644 --- a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs +++ b/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs @@ -1,9 +1,10 @@ #![feature(type_alias_impl_trait)] +// check-pass + type Foo = impl Fn() -> Foo; fn foo() -> Foo { -//~^ ERROR: overflow evaluating the requirement foo } diff --git a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr b/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr deleted file mode 100644 index 0a34e8486a5..00000000000 --- a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0275]: overflow evaluating the requirement `Foo: Sized` - --> $DIR/issue-53398-cyclic-types.rs:5:13 - | -LL | fn foo() -> Foo { - | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`) - = note: required because it appears within the type `fn() -> Foo {foo}` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/obligation_ice.rs b/tests/ui/type-alias-impl-trait/obligation_ice.rs new file mode 100644 index 00000000000..5aef04ff19c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/obligation_ice.rs @@ -0,0 +1,17 @@ +#![feature(type_alias_impl_trait)] +// check-pass + +use std::iter::{once, Chain}; + +trait Trait<'a, 'b: 'a> {} + +impl<'a, 'b: 'a, T> Trait<'a, 'b> for std::iter::Cloned {} + +type I<'a, 'b: 'a, A: Trait<'a, 'b>> = Chain>; +fn test2<'a, 'b, A: Trait<'a, 'b> + Iterator>(x: A) -> I<'a, 'b, A> { + x.chain(once("5")) +} + +fn main() { + assert_eq!(vec!["1", "3", "5"], test2(["1", "3"].iter().cloned()).collect::>()); +} diff --git a/tests/ui/type-alias-impl-trait/privacy.rs b/tests/ui/type-alias-impl-trait/privacy.rs new file mode 100644 index 00000000000..aa092f6f8ec --- /dev/null +++ b/tests/ui/type-alias-impl-trait/privacy.rs @@ -0,0 +1,8 @@ +#![feature(type_alias_impl_trait)] + +type Foo = (impl Sized, u8); +pub fn foo() -> Foo { + //~^ ERROR private type alias `Foo` in public interface + (42, 42) +} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/privacy.stderr b/tests/ui/type-alias-impl-trait/privacy.stderr new file mode 100644 index 00000000000..e8c6039cdc8 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/privacy.stderr @@ -0,0 +1,11 @@ +error[E0446]: private type alias `Foo` in public interface + --> $DIR/privacy.rs:4:1 + | +LL | type Foo = (impl Sized, u8); + | -------- `Foo` declared as private +LL | pub fn foo() -> Foo { + | ^^^^^^^^^^^^^^^^^^^ can't leak private type alias + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.rs b/tests/ui/type-alias-impl-trait/self-referential-3.rs index d40715717d4..18f09b54867 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-3.rs +++ b/tests/ui/type-alias-impl-trait/self-referential-3.rs @@ -1,9 +1,9 @@ -// run-pass #![feature(type_alias_impl_trait)] type Bar<'a, 'b> = impl PartialEq> + std::fmt::Debug; fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { + //~^ ERROR can't compare `&i32` with `Bar<'a, 'b>` i } diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.stderr b/tests/ui/type-alias-impl-trait/self-referential-3.stderr new file mode 100644 index 00000000000..4155a114b4f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/self-referential-3.stderr @@ -0,0 +1,15 @@ +error[E0277]: can't compare `&i32` with `Bar<'a, 'b>` + --> $DIR/self-referential-3.rs:5:31 + | +LL | fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { + | ^^^^^^^^^^^ no implementation for `&i32 == Bar<'a, 'b>` +LL | +LL | i + | - return type was inferred to be `&i32` here + | + = help: the trait `PartialEq>` is not implemented for `&i32` + = help: the trait `PartialEq` is implemented for `i32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/self-referential.rs b/tests/ui/type-alias-impl-trait/self-referential.rs index 3ff5406a382..34b7c24df9f 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.rs +++ b/tests/ui/type-alias-impl-trait/self-referential.rs @@ -10,7 +10,7 @@ fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> { type Foo<'a, 'b> = (i32, impl PartialEq> + std::fmt::Debug); fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { - //~^ ERROR can't compare `&i32` with `(i32, &i32)` + //~^ ERROR can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0})` (42, i) } diff --git a/tests/ui/type-alias-impl-trait/self-referential.stderr b/tests/ui/type-alias-impl-trait/self-referential.stderr index aff489d70e3..9a17d495b62 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential.stderr @@ -10,16 +10,16 @@ LL | i = help: the trait `PartialEq>` is not implemented for `&i32` = help: the trait `PartialEq` is implemented for `i32` -error[E0277]: can't compare `&i32` with `(i32, &i32)` +error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0})` --> $DIR/self-referential.rs:12:31 | LL | fn foo<'a, 'b>(i: &'a i32) -> Foo<'a, 'b> { - | ^^^^^^^^^^^ no implementation for `&i32 == (i32, &i32)` + | ^^^^^^^^^^^ no implementation for `&i32 == (i32, Foo<'a, 'b>::{opaque#0})` LL | LL | (42, i) | ------- return type was inferred to be `(i32, &i32)` here | - = help: the trait `PartialEq<(i32, &i32)>` is not implemented for `&i32` + = help: the trait `PartialEq<(i32, Foo<'a, 'b>::{opaque#0})>` is not implemented for `&i32` = help: the trait `PartialEq` is implemented for `i32` error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0})` diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fns.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fns.rs index 07c891f0638..4e7388517a5 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fns.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-fns.rs @@ -4,20 +4,20 @@ // Regression test for issue #61863 -pub trait MyTrait {} +trait MyTrait {} #[derive(Debug)] -pub struct MyStruct { +struct MyStruct { v: u64, } impl MyTrait for MyStruct {} -pub fn bla() -> TE { +fn bla() -> TE { return MyStruct { v: 1 }; } -pub fn bla2() -> TE { +fn bla2() -> TE { bla() } diff --git a/tests/ui/type-alias-impl-trait/unnameable_type.stderr b/tests/ui/type-alias-impl-trait/unnameable_type.stderr index e9032433494..24f5cc8c733 100644 --- a/tests/ui/type-alias-impl-trait/unnameable_type.stderr +++ b/tests/ui/type-alias-impl-trait/unnameable_type.stderr @@ -25,6 +25,11 @@ LL | fn dont_define_this(_private: Private) {} | ^^^^^^^ = note: expected signature `fn(Private)` found signature `fn(MyPrivate)` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/unnameable_type.rs:20:5 + | +LL | fn dont_define_this(_private: MyPrivate) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors