-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
87 changed files
with
625 additions
and
344 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
}, | ||
); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.