Auto merge of #108860 - oli-obk:tait_alias, r=compiler-errors

Add `AliasKind::Weak` for type aliases.

`type Foo<T: Debug> = Bar<T>;` does not check `T: Debug` at use sites of `Foo<NotDebug>`, because in contrast to a

```rust
trait Identity {
    type Identity;
}
impl<T: Debug> Identity for T {
    type Identity = T;
}
<NotDebug as Identity>::Identity
```

type aliases do not exist in the type system, but are expanded to their aliased type immediately when going from HIR to the type layer.

Similarly:

* a private type alias for a public type is a completely fine thing, even though it makes it a bit hard to write out complex times sometimes
* rustdoc expands the type alias, even though often times users use them for documentation purposes
* diagnostics show the expanded type, which is confusing if the user wrote a type alias and the diagnostic talks about another type that they don't know about.

For type alias impl trait, these issues do not actually apply in most cases, but sometimes you have a type alias impl trait like `type Foo<T: Debug> = (impl Debug, Bar<T>);`, which only really checks it for `impl Debug`, but by accident prevents `Bar<T>` from only being instantiated after proving `T: Debug`. This PR makes sure that we always check these bounds explicitly and don't rely on an implementation accident.

To not break all the type aliases out there, we only use it when the type alias contains an opaque type. We can decide to do this for all type aliases over an edition.

Or we can later extend this to more types if we figure out the back-compat concerns with suddenly checking such bounds.

As a side effect, easily allows fixing https://github.com/rust-lang/rust/issues/108617, which I did.

fixes https://github.com/rust-lang/rust/issues/108617
This commit is contained in:
bors 2023-06-17 00:33:29 +00:00
commit 0cc541e4b2
87 changed files with 625 additions and 344 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

@ -0,0 +1,124 @@
use rustc_ast::TraitObjectSyntax;
use rustc_errors::{Diagnostic, StashKey};
use rustc_hir as hir;
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use super::AstConv;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Make sure that we are in the condition to suggest the blanket implementation.
pub(super) fn maybe_lint_blanket_trait_impl(
&self,
self_ty: &hir::Ty<'_>,
diag: &mut Diagnostic,
) {
let tcx = self.tcx();
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
}),
..
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
{
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {}: {}", param_name, impl_trait_name))
} else {
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
};
diag.multipart_suggestion(
format!("alternatively use a blanket \
implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"),
vec![
(self_ty.span, param_name),
add_generic_sugg,
],
Applicability::MaybeIncorrect,
);
}
}
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
let tcx = self.tcx();
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
self_ty.kind
{
let needs_bracket = in_path
&& !tcx
.sess
.source_map()
.span_to_prev_source(self_ty.span)
.ok()
.is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
let mut sugg = Vec::from_iter([(
self_ty.span.shrink_to_lo(),
format!(
"{}dyn {}",
if needs_bracket { "<" } else { "" },
if is_global { "(" } else { "" },
),
)]);
if is_global || needs_bracket {
sugg.push((
self_ty.span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
));
}
if self_ty.span.edition().rust_2021() {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
if self_ty.span.can_be_used_for_suggestions() {
diag.multipart_suggestion_verbose(
label,
sugg,
Applicability::MachineApplicable,
);
}
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
} else {
let msg = "trait objects without an explicit `dyn` are deprecated";
tcx.struct_span_lint_hir(
BARE_TRAIT_OBJECTS,
self_ty.hir_id,
self_ty.span,
msg,
|lint| {
lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
lint
},
);
}
}
}
}

View File

@ -4,6 +4,7 @@
mod errors;
pub mod generics;
mod lint;
use crate::astconv::errors::prohibit_assoc_ty_binding;
use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args};
@ -19,7 +20,7 @@ use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
MultiSpan, StashKey,
MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@ -33,14 +34,12 @@ use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{DynKind, ToPredicate};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::error_reporting::{
report_object_safety_error, suggestions::NextTypeParamName,
};
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{
self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt,
@ -1458,7 +1457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
self.tcx().at(span).type_of(did).subst(self.tcx(), substs)
let ty = self.tcx().at(span).type_of(did);
if matches!(self.tcx().def_kind(did), DefKind::TyAlias)
&& ty.skip_binder().has_opaque_types()
{
// Type aliases referring to types that contain opaque types (but aren't just directly
// referencing a single opaque type) get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
let alias_ty = self.tcx().mk_alias_ty(did, substs);
self.tcx().mk_alias(ty::Weak, alias_ty)
} else {
ty.subst(self.tcx(), substs)
}
}
fn conv_object_ty_poly_trait_ref(
@ -3703,115 +3714,4 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Some(r)
}
/// Make sure that we are in the condition to suggest the blanket implementation.
fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
let tcx = self.tcx();
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
}),
..
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
{
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {}: {}", param_name, impl_trait_name))
} else {
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
};
diag.multipart_suggestion(
format!("alternatively use a blanket \
implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"),
vec![
(self_ty.span, param_name),
add_generic_sugg,
],
Applicability::MaybeIncorrect,
);
}
}
fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
let tcx = self.tcx();
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
self_ty.kind
{
let needs_bracket = in_path
&& !tcx
.sess
.source_map()
.span_to_prev_source(self_ty.span)
.ok()
.is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
let mut sugg = Vec::from_iter([(
self_ty.span.shrink_to_lo(),
format!(
"{}dyn {}",
if needs_bracket { "<" } else { "" },
if is_global { "(" } else { "" },
),
)]);
if is_global || needs_bracket {
sugg.push((
self_ty.span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
));
}
if self_ty.span.edition().rust_2021() {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
if self_ty.span.can_be_used_for_suggestions() {
diag.multipart_suggestion_verbose(
label,
sugg,
Applicability::MachineApplicable,
);
}
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
} else {
let msg = "trait objects without an explicit `dyn` are deprecated";
tcx.struct_span_lint_hir(
BARE_TRAIT_OBJECTS,
self_ty.hir_id,
self_ty.span,
msg,
|lint| {
lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
lint
},
);
}
}
}
}

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 tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
if let ty::Foreign(_) = tail.kind() {
forbid_unsized = false;
let forbid_unsized = match unsized_handling {
UnsizedHandling::Forbid => true,
UnsizedHandling::Allow => false,
UnsizedHandling::AllowIfForeignTail => {
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
!matches!(tail.kind(), ty::Foreign(_))
}
}
};
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
if forbid_unsized {

View File

@ -200,35 +200,32 @@ fn do_orphan_check_impl<'tcx>(
NonlocalImpl::DisallowOther,
),
// trait Id { type This: ?Sized; }
// impl<T: ?Sized> Id for T {
// type This = T;
// }
// impl<T: ?Sized> AutoTrait for <T as Id>::This {}
ty::Alias(AliasKind::Projection, _) => (
LocalImpl::Disallow { problematic_kind: "associated type" },
NonlocalImpl::DisallowOther,
),
// ```
// struct S<T>(T);
// impl<T: ?Sized> S<T> {
// type This = T;
// }
// impl<T: ?Sized> AutoTrait for S<T>::This {}
// ```
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
ty::Alias(AliasKind::Inherent, _) => (
LocalImpl::Disallow { problematic_kind: "associated type" },
NonlocalImpl::DisallowOther,
),
// type Opaque = impl Trait;
// impl AutoTrait for Opaque {}
ty::Alias(AliasKind::Opaque, _) => (
LocalImpl::Disallow { problematic_kind: "opaque type" },
NonlocalImpl::DisallowOther,
),
ty::Alias(kind, _) => {
let problematic_kind = match kind {
// trait Id { type This: ?Sized; }
// impl<T: ?Sized> Id for T {
// type This = T;
// }
// 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",
// ```
// struct S<T>(T);
// impl<T: ?Sized> S<T> {
// type This = T;
// }
// impl<T: ?Sized> AutoTrait for S<T>::This {}
// ```
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
AliasKind::Inherent => "associated type",
};
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
}
ty::Bool
| ty::Char

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

@ -510,10 +510,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Placeholder(..)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Alias(ty::Inherent, _)
| ty::Alias(ty::Weak, _)
| ty::Error(_) => return,
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty,
};

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,8 +1,8 @@
error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73249-2.rs:26:25
--> $DIR/lint-ctypes-73249-2.rs:26:21
|
LL | pub fn lint_me() -> A<()>;
| ^^^^^ not FFI-safe
LL | fn lint_me() -> A<()>;
| ^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here

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,8 +1,8 @@
error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-1.rs:23:25
--> $DIR/lint-ctypes-73251-1.rs:23:21
|
LL | pub fn lint_me() -> <u32 as Foo>::Assoc;
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
LL | fn lint_me() -> <u32 as Foo>::Assoc;
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here

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,8 +1,8 @@
error: `extern` block uses type `AliasA`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-2.rs:36:25
--> $DIR/lint-ctypes-73251-2.rs:36:21
|
LL | pub fn lint_me() -> <AliasB as TraitB>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
LL | fn lint_me() -> <AliasB as TraitB>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here

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,8 +1,8 @@
error: `extern` block uses type `A`, which is not FFI-safe
--> $DIR/opaque-ty-ffi-unsafe.rs:11:17
--> $DIR/opaque-ty-ffi-unsafe.rs:11:24
|
LL | pub fn a(_: A);
| ^ not FFI-safe
LL | pub(crate) fn a(_: A);
| ^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here

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