Auto merge of #82891 - cjgillot:monoparent, r=petrochenkov
Make def_key and HIR parenting consistent. r? `@petrochenkov`
This commit is contained in:
commit
32dce353de
@ -223,7 +223,7 @@ enum ImplTraitContext<'b, 'a> {
|
||||
/// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
|
||||
///
|
||||
/// Newly generated parameters should be inserted into the given `Vec`.
|
||||
Universal(&'b mut Vec<hir::GenericParam<'a>>),
|
||||
Universal(&'b mut Vec<hir::GenericParam<'a>>, LocalDefId),
|
||||
|
||||
/// Treat `impl Trait` as shorthand for a new opaque type.
|
||||
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
|
||||
@ -278,7 +278,7 @@ fn disallowed() -> Self {
|
||||
fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
|
||||
use self::ImplTraitContext::*;
|
||||
match self {
|
||||
Universal(params) => Universal(params),
|
||||
Universal(params, parent) => Universal(params, *parent),
|
||||
ReturnPositionOpaqueTy { fn_def_id, origin } => {
|
||||
ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin }
|
||||
}
|
||||
@ -475,25 +475,18 @@ struct MiscCollector<'tcx, 'lowering, 'hir> {
|
||||
}
|
||||
|
||||
impl MiscCollector<'_, '_, '_> {
|
||||
fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: LocalDefId) {
|
||||
fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) {
|
||||
match tree.kind {
|
||||
UseTreeKind::Simple(_, id1, id2) => {
|
||||
for &id in &[id1, id2] {
|
||||
self.lctx.resolver.create_def(
|
||||
owner,
|
||||
id,
|
||||
DefPathData::Misc,
|
||||
ExpnId::root(),
|
||||
tree.prefix.span,
|
||||
);
|
||||
self.lctx.allocate_hir_id_counter(id);
|
||||
}
|
||||
}
|
||||
UseTreeKind::Glob => (),
|
||||
UseTreeKind::Nested(ref trees) => {
|
||||
for &(ref use_tree, id) in trees {
|
||||
let hir_id = self.lctx.allocate_hir_id_counter(id);
|
||||
self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner);
|
||||
self.lctx.allocate_hir_id_counter(id);
|
||||
self.allocate_use_tree_hir_id_counters(use_tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -502,7 +495,7 @@ fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: LocalDefI
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> {
|
||||
fn visit_item(&mut self, item: &'tcx Item) {
|
||||
let hir_id = self.lctx.allocate_hir_id_counter(item.id);
|
||||
self.lctx.allocate_hir_id_counter(item.id);
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Struct(_, ref generics)
|
||||
@ -521,7 +514,7 @@ fn visit_item(&mut self, item: &'tcx Item) {
|
||||
self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count);
|
||||
}
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner);
|
||||
self.allocate_use_tree_hir_id_counters(use_tree);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -939,8 +932,13 @@ fn add_in_band_defs<T>(
|
||||
// `lifetimes_to_define`. If we swapped the order of these two,
|
||||
// in-band-lifetimes introduced by generics or where-clauses
|
||||
// wouldn't have been added yet.
|
||||
let generics =
|
||||
this.lower_generics_mut(generics, ImplTraitContext::Universal(&mut params));
|
||||
let generics = this.lower_generics_mut(
|
||||
generics,
|
||||
ImplTraitContext::Universal(
|
||||
&mut params,
|
||||
this.current_hir_id_owner.last().unwrap().0,
|
||||
),
|
||||
);
|
||||
let res = f(this, &mut params);
|
||||
(params, (generics, res))
|
||||
})
|
||||
@ -1145,6 +1143,7 @@ fn lower_assoc_ty_constraint(
|
||||
}
|
||||
AssocTyConstraintKind::Bound { ref bounds } => {
|
||||
let mut capturable_lifetimes;
|
||||
let mut parent_def_id = self.current_hir_id_owner.last().unwrap().0;
|
||||
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
|
||||
let (desugar_to_impl_trait, itctx) = match itctx {
|
||||
// We are in the return position:
|
||||
@ -1164,7 +1163,10 @@ fn lower_assoc_ty_constraint(
|
||||
// so desugar to
|
||||
//
|
||||
// fn foo(x: dyn Iterator<Item = impl Debug>)
|
||||
ImplTraitContext::Universal(..) if self.is_in_dyn_type => (true, itctx),
|
||||
ImplTraitContext::Universal(_, parent) if self.is_in_dyn_type => {
|
||||
parent_def_id = parent;
|
||||
(true, itctx)
|
||||
}
|
||||
|
||||
// In `type Foo = dyn Iterator<Item: Debug>` we desugar to
|
||||
// `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
|
||||
@ -1198,7 +1200,6 @@ fn lower_assoc_ty_constraint(
|
||||
// constructing the HIR for `impl bounds...` and then lowering that.
|
||||
|
||||
let impl_trait_node_id = self.resolver.next_node_id();
|
||||
let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
|
||||
self.resolver.create_def(
|
||||
parent_def_id,
|
||||
impl_trait_node_id,
|
||||
@ -1451,7 +1452,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
|
||||
|this| this.lower_param_bounds(bounds, nested_itctx),
|
||||
)
|
||||
}
|
||||
ImplTraitContext::Universal(in_band_ty_params) => {
|
||||
ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => {
|
||||
// Add a definition for the in-band `Param`.
|
||||
let def_id = self.resolver.local_def_id(def_node_id);
|
||||
|
||||
@ -1460,7 +1461,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
|
||||
let hir_bounds = self.with_hir_id_owner(def_node_id, |this| {
|
||||
this.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Universal(in_band_ty_params),
|
||||
ImplTraitContext::Universal(in_band_ty_params, parent_def_id),
|
||||
)
|
||||
});
|
||||
// Set the name to `impl Bound1 + Bound2`.
|
||||
@ -1891,7 +1892,13 @@ fn lower_fn_decl(
|
||||
}
|
||||
this.arena.alloc_from_iter(inputs.iter().map(|param| {
|
||||
if let Some((_, ibty)) = &mut in_band_ty_params {
|
||||
this.lower_ty_direct(¶m.ty, ImplTraitContext::Universal(ibty))
|
||||
this.lower_ty_direct(
|
||||
¶m.ty,
|
||||
ImplTraitContext::Universal(
|
||||
ibty,
|
||||
this.current_hir_id_owner.last().unwrap().0,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed())
|
||||
}
|
||||
|
@ -221,6 +221,18 @@ fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
|
||||
|
||||
data.signature =
|
||||
Some(self.arena.alloc(Owner { parent: entry.parent, node: entry.node }));
|
||||
|
||||
let dk_parent = self.definitions.def_key(id.owner).parent;
|
||||
if let Some(dk_parent) = dk_parent {
|
||||
let dk_parent = LocalDefId { local_def_index: dk_parent };
|
||||
let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
|
||||
if dk_parent.owner != entry.parent.owner {
|
||||
panic!(
|
||||
"Different parents for {:?} => dk_parent={:?} actual={:?}",
|
||||
id.owner, dk_parent, entry.parent,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert_eq!(entry.parent.owner, id.owner);
|
||||
insert_vec_map(
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::Resolver;
|
||||
use crate::{ImplTraitContext, Resolver};
|
||||
use rustc_ast::visit::{self, FnKind};
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_ast::*;
|
||||
@ -16,14 +16,15 @@
|
||||
fragment: &AstFragment,
|
||||
expansion: ExpnId,
|
||||
) {
|
||||
let parent_def = resolver.invocation_parents[&expansion];
|
||||
fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion });
|
||||
let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion];
|
||||
fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context });
|
||||
}
|
||||
|
||||
/// Creates `DefId`s for nodes in the AST.
|
||||
struct DefCollector<'a, 'b> {
|
||||
resolver: &'a mut Resolver<'b>,
|
||||
parent_def: LocalDefId,
|
||||
impl_trait_context: ImplTraitContext,
|
||||
expansion: ExpnId,
|
||||
}
|
||||
|
||||
@ -40,6 +41,16 @@ fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
|
||||
self.parent_def = orig_parent_def;
|
||||
}
|
||||
|
||||
fn with_impl_trait<F: FnOnce(&mut Self)>(
|
||||
&mut self,
|
||||
impl_trait_context: ImplTraitContext,
|
||||
f: F,
|
||||
) {
|
||||
let orig_itc = std::mem::replace(&mut self.impl_trait_context, impl_trait_context);
|
||||
f(self);
|
||||
self.impl_trait_context = orig_itc;
|
||||
}
|
||||
|
||||
fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
|
||||
let index = |this: &Self| {
|
||||
index.unwrap_or_else(|| {
|
||||
@ -60,8 +71,9 @@ fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
|
||||
}
|
||||
|
||||
fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
let id = id.placeholder_to_expn_id();
|
||||
let old_parent =
|
||||
self.resolver.invocation_parents.insert(id.placeholder_to_expn_id(), self.parent_def);
|
||||
self.resolver.invocation_parents.insert(id, (self.parent_def, self.impl_trait_context));
|
||||
assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
|
||||
}
|
||||
}
|
||||
@ -103,29 +115,37 @@ fn visit_item(&mut self, i: &'a Item) {
|
||||
let def = self.create_def(i.id, def_data, i.span);
|
||||
|
||||
self.with_parent(def, |this| {
|
||||
match i.kind {
|
||||
ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
|
||||
// If this is a unit or tuple-like struct, register the constructor.
|
||||
if let Some(ctor_hir_id) = struct_def.ctor_id() {
|
||||
this.create_def(ctor_hir_id, DefPathData::Ctor, i.span);
|
||||
this.with_impl_trait(ImplTraitContext::Existential, |this| {
|
||||
match i.kind {
|
||||
ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => {
|
||||
// If this is a unit or tuple-like struct, register the constructor.
|
||||
if let Some(ctor_hir_id) = struct_def.ctor_id() {
|
||||
this.create_def(ctor_hir_id, DefPathData::Ctor, i.span);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_item(this, i);
|
||||
visit::walk_item(this, i);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
if let FnKind::Fn(_, _, sig, _, body) = fn_kind {
|
||||
if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness {
|
||||
self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
|
||||
let return_impl_trait_id =
|
||||
self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
|
||||
|
||||
// For async functions, we need to create their inner defs inside of a
|
||||
// closure to match their desugared representation. Besides that,
|
||||
// we must mirror everything that `visit::walk_fn` below does.
|
||||
self.visit_fn_header(&sig.header);
|
||||
visit::walk_fn_decl(self, &sig.decl);
|
||||
for param in &sig.decl.inputs {
|
||||
self.visit_param(param);
|
||||
}
|
||||
self.with_parent(return_impl_trait_id, |this| {
|
||||
this.visit_fn_ret_ty(&sig.decl.output)
|
||||
});
|
||||
let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
|
||||
self.with_parent(closure_def, |this| walk_list!(this, visit_block, body));
|
||||
return;
|
||||
@ -137,6 +157,14 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
|
||||
fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
|
||||
self.create_def(id, DefPathData::Misc, use_tree.span);
|
||||
match use_tree.kind {
|
||||
UseTreeKind::Simple(_, id1, id2) => {
|
||||
self.create_def(id1, DefPathData::Misc, use_tree.prefix.span);
|
||||
self.create_def(id2, DefPathData::Misc, use_tree.prefix.span);
|
||||
}
|
||||
UseTreeKind::Glob => (),
|
||||
UseTreeKind::Nested(..) => {}
|
||||
}
|
||||
visit::walk_use_tree(self, use_tree, id);
|
||||
}
|
||||
|
||||
@ -191,7 +219,15 @@ fn visit_generic_param(&mut self, param: &'a GenericParam) {
|
||||
};
|
||||
self.create_def(param.id, def_path_data, param.ident.span);
|
||||
|
||||
visit::walk_generic_param(self, param);
|
||||
// impl-Trait can happen inside generic parameters, like
|
||||
// ```
|
||||
// fn foo<U: Iterator<Item = impl Clone>>() {}
|
||||
// ```
|
||||
//
|
||||
// In that case, the impl-trait is lowered as an additional generic parameter.
|
||||
self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| {
|
||||
visit::walk_generic_param(this, param)
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
|
||||
@ -244,8 +280,19 @@ fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
match ty.kind {
|
||||
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
|
||||
TyKind::ImplTrait(node_id, _) => {
|
||||
let parent_def = self.create_def(node_id, DefPathData::ImplTrait, ty.span);
|
||||
self.with_parent(parent_def, |this| visit::walk_ty(this, ty));
|
||||
let parent_def = match self.impl_trait_context {
|
||||
ImplTraitContext::Universal(item_def) => self.resolver.create_def(
|
||||
item_def,
|
||||
node_id,
|
||||
DefPathData::ImplTrait,
|
||||
self.expansion,
|
||||
ty.span,
|
||||
),
|
||||
ImplTraitContext::Existential => {
|
||||
self.create_def(node_id, DefPathData::ImplTrait, ty.span)
|
||||
}
|
||||
};
|
||||
self.with_parent(parent_def, |this| visit::walk_ty(this, ty))
|
||||
}
|
||||
_ => visit::walk_ty(self, ty),
|
||||
}
|
||||
@ -275,7 +322,13 @@ fn visit_field_pattern(&mut self, fp: &'a FieldPat) {
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, p: &'a Param) {
|
||||
if p.is_placeholder { self.visit_macro_invoc(p.id) } else { visit::walk_param(self, p) }
|
||||
if p.is_placeholder {
|
||||
self.visit_macro_invoc(p.id)
|
||||
} else {
|
||||
self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| {
|
||||
visit::walk_param(this, p)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called only when we are visiting an individual field
|
||||
|
@ -156,6 +156,12 @@ pub fn module(module: Module<'a>, resolver: &Resolver<'a>) -> ParentScope<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone)]
|
||||
enum ImplTraitContext {
|
||||
Existential,
|
||||
Universal(LocalDefId),
|
||||
}
|
||||
|
||||
#[derive(Eq)]
|
||||
struct BindingError {
|
||||
name: Symbol,
|
||||
@ -989,8 +995,9 @@ pub struct Resolver<'a> {
|
||||
/// Indices of unnamed struct or variant fields with unresolved attributes.
|
||||
placeholder_field_indices: FxHashMap<NodeId, usize>,
|
||||
/// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
|
||||
/// we know what parent node that fragment should be attached to thanks to this table.
|
||||
invocation_parents: FxHashMap<ExpnId, LocalDefId>,
|
||||
/// we know what parent node that fragment should be attached to thanks to this table,
|
||||
/// and how the `impl Trait` fragments were introduced.
|
||||
invocation_parents: FxHashMap<ExpnId, (LocalDefId, ImplTraitContext)>,
|
||||
|
||||
next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
|
||||
/// Some way to know that we are in a *trait* impl in `visit_assoc_item`.
|
||||
@ -1205,7 +1212,7 @@ pub fn new(
|
||||
node_id_to_def_id.insert(CRATE_NODE_ID, root);
|
||||
|
||||
let mut invocation_parents = FxHashMap::default();
|
||||
invocation_parents.insert(ExpnId::root(), root);
|
||||
invocation_parents.insert(ExpnId::root(), (root, ImplTraitContext::Existential));
|
||||
|
||||
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
|
||||
.opts
|
||||
|
@ -326,7 +326,7 @@ fn lint_node_id(&self, expn_id: ExpnId) -> NodeId {
|
||||
// nearest closing item - we should try to return the closest parent of the ExpnId
|
||||
self.invocation_parents
|
||||
.get(&expn_id)
|
||||
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
|
||||
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0])
|
||||
}
|
||||
|
||||
fn has_derive_copy(&self, expn_id: ExpnId) -> bool {
|
||||
|
@ -93,9 +93,6 @@
|
||||
59| 1| used_only_from_this_lib_crate_generic_function(some_vec);
|
||||
60| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs");
|
||||
61| 1|}
|
||||
------------------
|
||||
| Unexecuted instantiation: used_crate::use_this_lib_crate
|
||||
------------------
|
||||
62| |
|
||||
63| |// FIXME(#79651): `used_from_bin_crate_and_lib_crate_generic_function()` is covered and executed
|
||||
64| |// `2` times, but the coverage output also shows (at the bottom of the coverage report):
|
||||
|
@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/tls.rs:12:25
|
||||
|
|
||||
LL | unsafe { let _val = A; }
|
||||
| ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A))
|
||||
| ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
|
||||
|
||||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/tls.rs:19:26
|
||||
|
|
||||
LL | unsafe { let _val = &A; }
|
||||
| ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A))
|
||||
| ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
|
||||
|
||||
warning: skipping const checks
|
||||
|
|
||||
|
@ -12,7 +12,7 @@ note: generator is not `Send` as this value is used across a yield
|
||||
--> $DIR/generator-print-verbose-1.rs:35:9
|
||||
|
|
||||
LL | let _non_send_gen = make_non_send_generator();
|
||||
| ------------- has type `Opaque(DefId(0:24 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
|
||||
| ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
|
||||
LL | yield;
|
||||
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
|
||||
LL | };
|
||||
@ -30,10 +30,10 @@ LL | require_send(send_gen);
|
||||
= help: the trait `Sync` is not implemented for `RefCell<i32>`
|
||||
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
|
||||
= note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]`
|
||||
= note: required because it appears within the type `Opaque(DefId(0:29 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
|
||||
= note: required because it appears within the type `Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])`
|
||||
= note: required because it appears within the type `{Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}`
|
||||
= note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]`
|
||||
= note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
|
||||
= note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])`
|
||||
= note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}`
|
||||
= note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
20
src/test/ui/impl-trait/impl-trait-in-macro.rs
Normal file
20
src/test/ui/impl-trait/impl-trait-in-macro.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
macro_rules! i {
|
||||
($($tr:tt)*) => { impl $($tr)* };
|
||||
}
|
||||
|
||||
fn foo(x: i!(Debug), y: i!(Debug)) -> String {
|
||||
let mut a = x;
|
||||
a = y; //~ ERROR mismatched
|
||||
format!("{:?}", a)
|
||||
}
|
||||
|
||||
trait S<T> {}
|
||||
|
||||
fn much_universe<T: S<i!(Debug)>, U: IntoIterator<Item = i!(Iterator<Item = i!(Clone)>)>>(
|
||||
_: i!(Debug + Clone),
|
||||
) {
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/impl-trait/impl-trait-in-macro.stderr
Normal file
20
src/test/ui/impl-trait/impl-trait-in-macro.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/impl-trait-in-macro.rs:9:9
|
||||
|
|
||||
LL | ($($tr:tt)*) => { impl $($tr)* };
|
||||
| ----
|
||||
| |
|
||||
| expected type parameter
|
||||
| found type parameter
|
||||
...
|
||||
LL | a = y;
|
||||
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
||||
|
|
||||
= note: expected type parameter `impl Debug` (type parameter `impl Debug`)
|
||||
found type parameter `impl Debug` (type parameter `impl Debug`)
|
||||
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -6,4 +6,11 @@ fn foo(x: impl Debug, y: impl Debug) -> String {
|
||||
format!("{:?}", a)
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
trait S<T> {}
|
||||
|
||||
fn much_universe<T: S<impl Debug>, U: IntoIterator<Item = impl Iterator<Item = impl Clone>>>(
|
||||
_: impl Debug + Clone,
|
||||
) {
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
Loading…
Reference in New Issue
Block a user