Add AliasKind::Weak for type aliases.

Only use it when the type alias contains an opaque type.

Also does wf-checking on such type aliases.
This commit is contained in:
Oli Scherer 2023-03-07 12:03:11 +00:00
parent 4fdd07fe88
commit f3b7dd6388
86 changed files with 474 additions and 199 deletions

View File

@ -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`"),

View File

@ -1458,7 +1458,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(

View File

@ -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 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);
if let ty::Foreign(_) = tail.kind() {
forbid_unsized = false;
}
!matches!(tail.kind(), ty::Foreign(_))
}
};
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
if forbid_unsized {

View File

@ -208,6 +208,9 @@ fn do_orphan_check_impl<'tcx>(
// }
// impl<T: ?Sized> AutoTrait for <T as Id>::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",

View File

@ -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)

View File

@ -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

View File

@ -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),
},
};

View File

@ -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() {

View File

@ -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(_)

View File

@ -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>

View File

@ -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.

View File

@ -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))
}

View File

@ -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(),
}

View File

@ -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,
});

View File

@ -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)
{

View File

@ -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!

View File

@ -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:?}"),
}
}

View File

@ -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

View File

@ -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`"),
}

View File

@ -508,10 +508,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,
};

View File

@ -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(_) => {

View File

@ -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;

View File

@ -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)),
}
}

View File

@ -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}`"),

View File

@ -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)
}
}

View File

@ -695,7 +695,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> 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),

View File

@ -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,
}
}

View File

@ -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,

View File

@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId;
pub use rustc_middle::traits::query::OutlivesBound;
type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
pub trait InferCtxtExt<'a, 'tcx> {
fn implied_outlives_bounds(
&self,

View File

@ -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<TyCtxt<'tcx>> 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)
}

View File

@ -257,7 +257,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> 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<TyCtxt<'tcx>> 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!(),
}?;

View File

@ -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!(

View File

@ -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)
}

View File

@ -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);

View File

@ -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
//

View File

@ -372,6 +372,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> 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 {

View File

@ -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>,

View File

@ -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 `<Type as Trait>::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.

View File

@ -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)

View File

@ -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)

View File

@ -82,10 +82,4 @@ fn msrv_1_41() {
}
}
type Opaque = impl Sized;
struct IntoOpaque;
impl Into<Opaque> for IntoOpaque {
fn into(self) -> Opaque {}
}
fn main() {}

View File

@ -82,10 +82,4 @@ fn msrv_1_41() {
}
}
type Opaque = impl Sized;
struct IntoOpaque;
impl Into<Opaque> for IntoOpaque {
fn into(self) -> Opaque {}
}
fn main() {}

View File

@ -32,4 +32,10 @@ impl Into<u8> for ContainsVal {
}
}
type Opaque = impl Sized;
struct IntoOpaque;
impl Into<Opaque> for IntoOpaque {
fn into(self) -> Opaque {}
}
fn main() {}

View File

@ -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<InMacro> for String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | type Opaque = impl Sized;
| ^^^^^^^^^^
|
= help: replace the `Into` implementation with `From<std::string::String>`
= note: `-D clippy::from-over-into` implied by `-D warnings`
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/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<WeirdUpperSelf> 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<u8> for ContainsVal {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `impl From<Local> 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<ContainsVal>`
error: aborting due to 3 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -401,25 +401,3 @@ mod issue7344 {
}
}
}
mod issue10041 {
struct Bomb;
impl Bomb {
// Hidden <Rhs = Self> default generic parameter.
pub fn new() -> impl PartialOrd {
0i32
}
}
// TAIT with self-referencing bounds
type X = impl std::ops::Add<Output = X>;
struct Bomb2;
impl Bomb2 {
pub fn new() -> X {
0i32
}
}
}

View File

@ -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

View File

@ -0,0 +1,26 @@
#![feature(type_alias_impl_trait)]
#![warn(clippy::new_ret_no_self)]
mod issue10041 {
struct Bomb;
impl Bomb {
// Hidden <Rhs = Self> default generic parameter.
pub fn new() -> impl PartialOrd {
0i32
}
}
// TAIT with self-referencing bounds
type X = impl std::ops::Add<Output = X>;
struct Bomb2;
impl Bomb2 {
pub fn new() -> X {
0i32
}
}
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0275]: overflow evaluating the requirement `<i32 as std::ops::Add>::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`.

View File

@ -8,10 +8,6 @@ LL | fn foo() -> impl Trait<Assoc = Sendable> {
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
help: add this bound
|
LL | type Sendable = impl Send + Duh;
| +++++
warning: 1 warning emitted

View File

@ -8,10 +8,6 @@ LL | fn foo() -> impl Trait<Assoc = Sendable> {
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
help: add this bound
|
LL | type Sendable = impl Send + Duh;
| +++++
warning: 1 warning emitted

View File

@ -8,10 +8,6 @@ LL | type Traitable = impl Trait<Assoc = Sendable>;
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(opaque_hidden_inferred_bound)]` on by default
help: add this bound
|
LL | type Sendable = impl Send + Duh;
| +++++
warning: 1 warning emitted

View File

@ -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
}

View File

@ -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`.

View File

@ -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

View File

@ -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
}

View File

@ -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`.

View File

@ -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<T: Foo> {
struct A<T: Foo> {
x: &'static <T as Foo>::Assoc,
}
extern "C" {
pub fn lint_me() -> A<()>; //~ ERROR: uses type `Qux`
fn lint_me() -> A<()>; //~ ERROR: uses type `Qux`
}
fn main() {}

View File

@ -1,7 +1,7 @@
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<()>;
LL | fn lint_me() -> A<()>;
| ^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent

View File

@ -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() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `Qux`
fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `Qux`
}
fn main() {}

View File

@ -1,7 +1,7 @@
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() -> <u32 as Foo>::Assoc;
LL | fn lint_me() -> <u32 as Foo>::Assoc;
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent

View File

@ -33,7 +33,7 @@ fn use_of_b() -> AliasB {
}
extern "C" {
pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `AliasA`
fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `AliasA`
}
fn main() {}

View File

@ -1,7 +1,7 @@
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() -> <AliasB as TraitB>::Assoc;
LL | fn lint_me() -> <AliasB as TraitB>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent

View File

@ -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<Assoc = u32>;
fn assign() -> Bar {}
extern "C" {
pub fn lint_me() -> <Bar as Foo>::Assoc;
fn lint_me() -> <Bar as Foo>::Assoc;
}
fn main() {}

View File

@ -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]
}

View File

@ -1,7 +1,7 @@
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);
LL | pub(crate) fn a(_: A);
| ^ not FFI-safe
|
= note: opaque types have no C equivalent

View File

@ -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
}
}

View File

@ -0,0 +1,16 @@
#![feature(type_alias_impl_trait)]
use std::fmt::{Debug, Display};
struct Struct<V: Display>(Option<V>);
// Make sure that, in contrast to type aliases without opaque types,
// we actually do a wf check for the aliased type.
type Foo<T: Debug> = (impl Debug, Struct<T>);
//~^ ERROR: `T` doesn't implement `std::fmt::Display`
fn foo<U: Debug + Display>() -> Foo<U> {
(Vec::<U>::new(), Struct(None))
}
fn main() {}

View File

@ -0,0 +1,20 @@
error[E0277]: `T` doesn't implement `std::fmt::Display`
--> $DIR/bounds-are-checked3.rs:9:35
|
LL | type Foo<T: Debug> = (impl Debug, Struct<T>);
| ^^^^^^^^^ `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<V: Display>(Option<V>);
| ^^^^^^^ required by this bound in `Struct`
help: consider further restricting this bound
|
LL | type Foo<T: Debug + std::fmt::Display> = (impl Debug, Struct<T>);
| +++++++++++++++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -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<T: Debug> = (impl Debug, usize);
fn foo<U: Debug>() -> Foo<U> {
(Vec::<U>::new(), 1234)
}
fn main() {}

View File

@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar
LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------
| | |
| | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
| | `AliasOfForeignType<T>` 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

View File

@ -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
}
}

View File

@ -4,11 +4,11 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
| ^^^^^^^^^^^^^^^^^^^ 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<T: Trait> = impl Send;
| ^^^^^ required by this bound in `Underconstrained`
| ^^^^^ required by this bound
help: consider restricting type parameter `T`
|
LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {

View File

@ -4,11 +4,11 @@ error[E0277]: `U` doesn't implement `Debug`
LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
| ^^^^^^^^^^^^^^^^^^^ `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<T: std::fmt::Debug> = impl Send;
| ^^^^^^^^^^^^^^^ required by this bound in `Underconstrained`
| ^^^^^^^^^^^^^^^ required by this bound
help: consider restricting type parameter `U`
|
LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> {
@ -20,11 +20,11 @@ error[E0277]: `V` doesn't implement `Debug`
LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
| ^^^^^^^^^^^^^^^^^^^^ `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<T: std::fmt::Debug> = impl Send;
| ^^^^^^^^^^^^^^^ required by this bound in `Underconstrained2`
| ^^^^^^^^^^^^^^^ required by this bound
help: consider restricting type parameter `V`
|
LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> {

View File

@ -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() {}

View File

@ -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`.

View File

@ -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
}

View File

@ -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`.

View File

@ -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<T> {}
type I<'a, 'b: 'a, A: Trait<'a, 'b>> = Chain<A, impl Iterator<Item = &'static str>>;
fn test2<'a, 'b, A: Trait<'a, 'b> + Iterator<Item = &'static str>>(x: A) -> I<'a, 'b, A> {
x.chain(once("5"))
}
fn main() {
assert_eq!(vec!["1", "3", "5"], test2(["1", "3"].iter().cloned()).collect::<Vec<_>>());
}

View File

@ -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() {}

View File

@ -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`.

View File

@ -1,9 +1,9 @@
// run-pass
#![feature(type_alias_impl_trait)]
type Bar<'a, 'b> = impl PartialEq<Bar<'a, 'b>> + std::fmt::Debug;
fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
//~^ ERROR can't compare `&i32` with `Bar<'a, 'b>`
i
}

View File

@ -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<Bar<'a, 'b>>` 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`.

View File

@ -10,7 +10,7 @@ fn bar<'a, 'b>(i: &'a i32) -> Bar<'a, 'b> {
type Foo<'a, 'b> = (i32, impl PartialEq<Foo<'a, 'b>> + 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)
}

View File

@ -10,16 +10,16 @@ LL | i
= help: the trait `PartialEq<Bar<'b, 'a>>` 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})`

View File

@ -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()
}

View File

@ -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