Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't assume traits used as type are trait objs in 2021 edition #131239

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 25 additions & 28 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_ast::TraitObjectSyntax;
use rustc_errors::codes::*;
use rustc_errors::{Diag, EmissionGuarantee, StashKey};
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_lint_defs::Applicability;
Expand All @@ -15,13 +15,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
///
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
/// In edition 2021 and onward we emit a hard error for them.
pub(super) fn prohibit_or_lint_bare_trait_object_ty(&self, self_ty: &hir::Ty<'_>) {
pub(super) fn prohibit_or_lint_bare_trait_object_ty(
&self,
self_ty: &hir::Ty<'_>,
) -> Option<ErrorGuaranteed> {
let tcx = self.tcx();

let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
self_ty.kind
else {
return;
return None;
};

let in_path = match tcx.parent_hir_node(self_ty.hir_id) {
Expand Down Expand Up @@ -70,8 +73,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}

if self_ty.span.edition().at_least_rust_2021() {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let msg = "expected a type, found a trait";
let label = "you can add the `dyn` keyword if you want a trait object";
let mut diag =
rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg);
if self_ty.span.can_be_used_for_suggestions()
Expand All @@ -83,7 +86,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Check if the impl trait that we are considering is an impl of a local trait.
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
// In case there is an associate type with the same name
// Add the suggestion to this error
if let Some(mut sugg) =
VulnBandit marked this conversation as resolved.
Show resolved Hide resolved
tcx.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
&& let Suggestions::Enabled(ref mut s1) = diag.suggestions
&& let Suggestions::Enabled(ref mut s2) = sugg.suggestions
{
s1.append(s2);
sugg.cancel();
}
diag.stash(self_ty.span, StashKey::TraitMissingMethod)
} else {
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| {
lint.primary_message("trait objects without an explicit `dyn` are deprecated");
Expand All @@ -96,6 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
self.maybe_suggest_blanket_trait_impl(self_ty, lint);
});
None
}
}

Expand Down Expand Up @@ -174,41 +188,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// 1. Independent functions
// 2. Functions inside trait blocks
// 3. Functions inside impl blocks
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
(sig, generics, None)
(sig, generics)
}
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, _),
generics,
owner_id,
..
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
}) => (sig, generics),
hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(sig, _),
generics,
owner_id,
..
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
}) => (sig, generics),
_ => return false,
};
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
return false;
};
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
let mut is_downgradable = true;

// Check if trait object is safe for suggesting dynamic dispatch.
let is_dyn_compatible = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|(o, _)| match o.trait_ref.path.res {
Res::Def(DefKind::Trait, id) => {
if Some(id) == owner {
// For recursive traits, don't downgrade the error. (#119652)
is_downgradable = false;
}
tcx.is_dyn_compatible(id)
}
Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
_ => false,
})
}
Expand Down Expand Up @@ -255,9 +259,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
suggestion,
Applicability::MachineApplicable,
);
} else if is_downgradable {
// We'll emit the dyn-compatibility error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
}
return true;
}
Expand All @@ -281,10 +282,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
if !is_dyn_compatible {
diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`"));
if is_downgradable {
// We'll emit the dyn-compatibility error already, with a structured suggestion.
diag.downgrade_to_delayed_bug();
}
} else {
// No ampersand in suggestion if it's borrowed already
let (dyn_str, paren_dyn_str) =
Expand Down
19 changes: 12 additions & 7 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2063,13 +2063,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
}
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
self.prohibit_or_lint_bare_trait_object_ty(hir_ty);

let repr = match repr {
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
TraitObjectSyntax::DynStar => ty::DynStar,
};
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
// Don't continue with type analysis if the `dyn` keyword is missing
// It generates confusing errors, especially if the user meant to use another
// keyword like `impl`
Ty::new_error(tcx, guar)
} else {
let repr = match repr {
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
TraitObjectSyntax::DynStar => ty::DynStar,
};
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
}
}
// If we encounter a fully qualified path with RTN generics, then it must have
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
Expand Down
10 changes: 0 additions & 10 deletions tests/crashes/120241-2.rs

This file was deleted.

13 changes: 0 additions & 13 deletions tests/crashes/120241.rs

This file was deleted.

13 changes: 0 additions & 13 deletions tests/crashes/120482.rs

This file was deleted.

10 changes: 0 additions & 10 deletions tests/crashes/125512.rs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,24 @@
//@ edition: 2021

fn f(_: impl Trait<T = Copy>) {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~^ ERROR expected a type, found a trait
//~| HELP you can add the `dyn` keyword if you want a trait object
//~| HELP you might have meant to write a bound here
//~| ERROR the trait `Copy` cannot be made into an object

fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~^ ERROR expected a type, found a trait
//~| HELP you can add the `dyn` keyword if you want a trait object
//~| HELP you might have meant to write a bound here
//~| ERROR only auto traits can be used as additional traits in a trait object
//~| HELP consider creating a new trait
//~| ERROR the trait `Eq` cannot be made into an object

fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~^ ERROR expected a type, found a trait
//~| HELP you can add the `dyn` keyword if you want a trait object
//~| HELP you might have meant to write a bound here

// Don't suggest assoc ty bound in trait object types, that's not valid:
type Obj = dyn Trait<T = Clone>;
//~^ ERROR trait objects must include the `dyn` keyword
//~| HELP add `dyn` keyword before this trait
//~^ ERROR expected a type, found a trait
//~| HELP you can add the `dyn` keyword if you want a trait object

trait Trait { type T; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,10 @@
error[E0038]: the trait `Copy` cannot be made into an object
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:20
|
LL | fn f(_: impl Trait<T = Copy>) {}
| ^^^^^^^^ `Copy` cannot be made into an object
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
= note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>

error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:42
|
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
| --------------- ^^ additional non-auto trait
| |
| first non-auto trait
|
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Debug + Eq {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>

error[E0038]: the trait `Eq` cannot be made into an object
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
|
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
| ^^^^^^^^^^^^^^^^^^^^ `Eq` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
= note: the trait cannot be made into an object because it uses `Self` as a type parameter

error[E0782]: trait objects must include the `dyn` keyword
error[E0782]: expected a type, found a trait
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:24
|
LL | fn f(_: impl Trait<T = Copy>) {}
| ^^^^
|
help: add `dyn` keyword before this trait
help: you can add the `dyn` keyword if you want a trait object
|
LL | fn f(_: impl Trait<T = dyn Copy>) {}
| +++
Expand All @@ -44,13 +13,13 @@ help: you might have meant to write a bound here
LL | fn f(_: impl Trait<T: Copy>) {}
| ~

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24
error[E0782]: expected a type, found a trait
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:9:24
|
LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {}
| ^^^^^^^^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
help: you can add the `dyn` keyword if you want a trait object
|
LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {}
| +++
Expand All @@ -59,13 +28,13 @@ help: you might have meant to write a bound here
LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {}
| ~

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26
error[E0782]: expected a type, found a trait
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:14:26
|
LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add `dyn` keyword before this trait
help: you can add the `dyn` keyword if you want a trait object
|
LL | fn h(_: impl Trait<T<> = dyn 'static + for<'a> Fn(&'a ())>) {}
| +++
Expand All @@ -74,18 +43,17 @@ help: you might have meant to write a bound here
LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {}
| ~

error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:24:26
error[E0782]: expected a type, found a trait
--> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:20:26
|
LL | type Obj = dyn Trait<T = Clone>;
| ^^^^^
|
help: add `dyn` keyword before this trait
help: you can add the `dyn` keyword if you want a trait object
|
LL | type Obj = dyn Trait<T = dyn Clone>;
| +++

error: aborting due to 7 previous errors
error: aborting due to 4 previous errors

Some errors have detailed explanations: E0038, E0225, E0782.
For more information about an error, try `rustc --explain E0038`.
For more information about this error, try `rustc --explain E0782`.
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ fn f<T>(
1
}],
) -> impl Iterator<Item = SubAssign> {
//~^ ERROR the type parameter `Rhs` must be explicitly specified
//~^ ERROR expected a type, found a trait
//~| ERROR `()` is not an iterator
//~| ERROR trait objects must include the `dyn` keyword
//~| ERROR the type parameter `Rhs` must be explicitly specified [E0393]
}

pub fn main() {}
Loading
Loading