mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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:
commit
0cc541e4b2
@ -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`"),
|
||||
|
124
compiler/rustc_hir_analysis/src/astconv/lint.rs
Normal file
124
compiler/rustc_hir_analysis/src/astconv/lint.rs
Normal 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
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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`"),
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,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
|
||||
|
@ -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,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
|
||||
|
@ -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,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
|
||||
|
@ -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,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
|
||||
|
@ -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