mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
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:
parent
4fdd07fe88
commit
f3b7dd6388
@ -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`"),
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
@ -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() {
|
||||
|
@ -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(_)
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
|
@ -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,
|
||||
});
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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!
|
||||
|
@ -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:?}"),
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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`"),
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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(_) => {
|
||||
|
@ -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;
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
@ -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}`"),
|
||||
|
19
compiler/rustc_trait_selection/src/solve/weak_types.rs
Normal file
19
compiler/rustc_trait_selection/src/solve/weak_types.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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),
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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!(),
|
||||
}?;
|
||||
|
@ -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!(
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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 {
|
||||
|
@ -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>,
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
26
src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs
Normal file
26
src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs
Normal 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() {}
|
@ -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`.
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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`.
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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`.
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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]
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
16
tests/ui/type-alias-impl-trait/bounds-are-checked3.rs
Normal file
16
tests/ui/type-alias-impl-trait/bounds-are-checked3.rs
Normal 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() {}
|
20
tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr
Normal file
20
tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr
Normal 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`.
|
16
tests/ui/type-alias-impl-trait/bounds.rs
Normal file
16
tests/ui/type-alias-impl-trait/bounds.rs
Normal 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() {}
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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> {
|
||||
|
14
tests/ui/type-alias-impl-trait/impl_for_weak_alias.rs
Normal file
14
tests/ui/type-alias-impl-trait/impl_for_weak_alias.rs
Normal 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() {}
|
11
tests/ui/type-alias-impl-trait/impl_for_weak_alias.stderr
Normal file
11
tests/ui/type-alias-impl-trait/impl_for_weak_alias.stderr
Normal 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`.
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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`.
|
17
tests/ui/type-alias-impl-trait/obligation_ice.rs
Normal file
17
tests/ui/type-alias-impl-trait/obligation_ice.rs
Normal 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<_>>());
|
||||
}
|
8
tests/ui/type-alias-impl-trait/privacy.rs
Normal file
8
tests/ui/type-alias-impl-trait/privacy.rs
Normal 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() {}
|
11
tests/ui/type-alias-impl-trait/privacy.stderr
Normal file
11
tests/ui/type-alias-impl-trait/privacy.stderr
Normal 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`.
|
@ -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
|
||||
}
|
||||
|
||||
|
15
tests/ui/type-alias-impl-trait/self-referential-3.stderr
Normal file
15
tests/ui/type-alias-impl-trait/self-referential-3.stderr
Normal 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`.
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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})`
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user