Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0cc541e

Browse files
committedJun 17, 2023
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 #108617, which I did. fixes #108617
2 parents 670a0ed + 79c2c98 commit 0cc541e

File tree

87 files changed

+625
-344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+625
-344
lines changed
 

‎compiler/rustc_hir_analysis/src/astconv/mod.rs

+17-117
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
mod errors;
66
pub mod generics;
7+
mod lint;
78

89
use crate::astconv::errors::prohibit_assoc_ty_binding;
910
use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args};
@@ -19,7 +20,7 @@ use rustc_ast::TraitObjectSyntax;
1920
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2021
use rustc_errors::{
2122
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
22-
MultiSpan, StashKey,
23+
MultiSpan,
2324
};
2425
use rustc_hir as hir;
2526
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -33,14 +34,12 @@ use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
3334
use rustc_middle::ty::GenericParamDefKind;
3435
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
3536
use rustc_middle::ty::{DynKind, ToPredicate};
36-
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
37+
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
3738
use rustc_span::edit_distance::find_best_match_for_name;
3839
use rustc_span::symbol::{kw, Ident, Symbol};
3940
use rustc_span::{sym, Span, DUMMY_SP};
4041
use rustc_target::spec::abi;
41-
use rustc_trait_selection::traits::error_reporting::{
42-
report_object_safety_error, suggestions::NextTypeParamName,
43-
};
42+
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
4443
use rustc_trait_selection::traits::wf::object_region_bounds;
4544
use rustc_trait_selection::traits::{
4645
self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt,
@@ -1458,7 +1457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14581457
item_segment: &hir::PathSegment<'_>,
14591458
) -> Ty<'tcx> {
14601459
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
1461-
self.tcx().at(span).type_of(did).subst(self.tcx(), substs)
1460+
let ty = self.tcx().at(span).type_of(did);
1461+
1462+
if matches!(self.tcx().def_kind(did), DefKind::TyAlias)
1463+
&& ty.skip_binder().has_opaque_types()
1464+
{
1465+
// Type aliases referring to types that contain opaque types (but aren't just directly
1466+
// referencing a single opaque type) get encoded as a type alias that normalization will
1467+
// then actually instantiate the where bounds of.
1468+
let alias_ty = self.tcx().mk_alias_ty(did, substs);
1469+
self.tcx().mk_alias(ty::Weak, alias_ty)
1470+
} else {
1471+
ty.subst(self.tcx(), substs)
1472+
}
14621473
}
14631474

14641475
fn conv_object_ty_poly_trait_ref(
@@ -3703,115 +3714,4 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
37033714
}
37043715
Some(r)
37053716
}
3706-
3707-
/// Make sure that we are in the condition to suggest the blanket implementation.
3708-
fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
3709-
let tcx = self.tcx();
3710-
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
3711-
if let hir::Node::Item(hir::Item {
3712-
kind:
3713-
hir::ItemKind::Impl(hir::Impl {
3714-
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
3715-
}),
3716-
..
3717-
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
3718-
{
3719-
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
3720-
return;
3721-
}
3722-
let of_trait_span = of_trait_ref.path.span;
3723-
// make sure that we are not calling unwrap to abort during the compilation
3724-
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
3725-
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
3726-
// check if the trait has generics, to make a correct suggestion
3727-
let param_name = generics.params.next_type_param_name(None);
3728-
3729-
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
3730-
(span, format!(", {}: {}", param_name, impl_trait_name))
3731-
} else {
3732-
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
3733-
};
3734-
diag.multipart_suggestion(
3735-
format!("alternatively use a blanket \
3736-
implementation to implement `{of_trait_name}` for \
3737-
all types that also implement `{impl_trait_name}`"),
3738-
vec![
3739-
(self_ty.span, param_name),
3740-
add_generic_sugg,
3741-
],
3742-
Applicability::MaybeIncorrect,
3743-
);
3744-
}
3745-
}
3746-
3747-
fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
3748-
let tcx = self.tcx();
3749-
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
3750-
self_ty.kind
3751-
{
3752-
let needs_bracket = in_path
3753-
&& !tcx
3754-
.sess
3755-
.source_map()
3756-
.span_to_prev_source(self_ty.span)
3757-
.ok()
3758-
.is_some_and(|s| s.trim_end().ends_with('<'));
3759-
3760-
let is_global = poly_trait_ref.trait_ref.path.is_global();
3761-
3762-
let mut sugg = Vec::from_iter([(
3763-
self_ty.span.shrink_to_lo(),
3764-
format!(
3765-
"{}dyn {}",
3766-
if needs_bracket { "<" } else { "" },
3767-
if is_global { "(" } else { "" },
3768-
),
3769-
)]);
3770-
3771-
if is_global || needs_bracket {
3772-
sugg.push((
3773-
self_ty.span.shrink_to_hi(),
3774-
format!(
3775-
"{}{}",
3776-
if is_global { ")" } else { "" },
3777-
if needs_bracket { ">" } else { "" },
3778-
),
3779-
));
3780-
}
3781-
3782-
if self_ty.span.edition().rust_2021() {
3783-
let msg = "trait objects must include the `dyn` keyword";
3784-
let label = "add `dyn` keyword before this trait";
3785-
let mut diag =
3786-
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
3787-
if self_ty.span.can_be_used_for_suggestions() {
3788-
diag.multipart_suggestion_verbose(
3789-
label,
3790-
sugg,
3791-
Applicability::MachineApplicable,
3792-
);
3793-
}
3794-
// check if the impl trait that we are considering is a impl of a local trait
3795-
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
3796-
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
3797-
} else {
3798-
let msg = "trait objects without an explicit `dyn` are deprecated";
3799-
tcx.struct_span_lint_hir(
3800-
BARE_TRAIT_OBJECTS,
3801-
self_ty.hir_id,
3802-
self_ty.span,
3803-
msg,
3804-
|lint| {
3805-
lint.multipart_suggestion_verbose(
3806-
"use `dyn`",
3807-
sugg,
3808-
Applicability::MachineApplicable,
3809-
);
3810-
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
3811-
lint
3812-
},
3813-
);
3814-
}
3815-
}
3816-
}
38173717
}

‎compiler/rustc_hir_analysis/src/check/wfcheck.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
217217
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl);
218218
}
219219
hir::ItemKind::Static(ty, ..) => {
220-
check_item_type(tcx, def_id, ty.span, false);
220+
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
221221
}
222222
hir::ItemKind::Const(ty, ..) => {
223-
check_item_type(tcx, def_id, ty.span, false);
223+
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
224224
}
225225
hir::ItemKind::Struct(_, ast_generics) => {
226226
check_type_defn(tcx, item, false);
@@ -242,6 +242,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
242242
}
243243
// `ForeignItem`s are handled separately.
244244
hir::ItemKind::ForeignMod { .. } => {}
245+
hir::ItemKind::TyAlias(hir_ty, ..) => {
246+
if tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
247+
// Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
248+
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
249+
}
250+
}
245251
_ => {}
246252
}
247253
}
@@ -258,7 +264,9 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
258264
hir::ForeignItemKind::Fn(decl, ..) => {
259265
check_item_fn(tcx, def_id, item.ident, item.span, decl)
260266
}
261-
hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true),
267+
hir::ForeignItemKind::Static(ty, ..) => {
268+
check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
269+
}
262270
hir::ForeignItemKind::Type => (),
263271
}
264272
}
@@ -1100,20 +1108,32 @@ fn check_item_fn(
11001108
})
11011109
}
11021110

1103-
fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) {
1111+
enum UnsizedHandling {
1112+
Forbid,
1113+
Allow,
1114+
AllowIfForeignTail,
1115+
}
1116+
1117+
fn check_item_type(
1118+
tcx: TyCtxt<'_>,
1119+
item_id: LocalDefId,
1120+
ty_span: Span,
1121+
unsized_handling: UnsizedHandling,
1122+
) {
11041123
debug!("check_item_type: {:?}", item_id);
11051124

11061125
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
11071126
let ty = tcx.type_of(item_id).subst_identity();
11081127
let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
11091128

1110-
let mut forbid_unsized = true;
1111-
if allow_foreign_ty {
1112-
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
1113-
if let ty::Foreign(_) = tail.kind() {
1114-
forbid_unsized = false;
1129+
let forbid_unsized = match unsized_handling {
1130+
UnsizedHandling::Forbid => true,
1131+
UnsizedHandling::Allow => false,
1132+
UnsizedHandling::AllowIfForeignTail => {
1133+
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
1134+
!matches!(tail.kind(), ty::Foreign(_))
11151135
}
1116-
}
1136+
};
11171137

11181138
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
11191139
if forbid_unsized {
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.