Fix generic argument lookup for Self
Rewrite the SelfCtor early and use the replacement Def when calculating the path_segs. Note that this also changes which def is seen by the code that computes user_self_ty and is_alias_variant_ctor; I don't see a immediate issue with that, but I'm not 100% clear on the implications. Fixes #57924
This commit is contained in:
parent
b58a0061a3
commit
311025e6a5
@ -5302,6 +5302,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
Some(original_span.with_lo(original_span.hi() - BytePos(1)))
|
Some(original_span.with_lo(original_span.hi() - BytePos(1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rewrite `SelfCtor` to `StructCtor`
|
||||||
|
pub fn rewrite_self_ctor(&self, def: Def, span: Span) -> (Def, DefId, Ty<'tcx>) {
|
||||||
|
let tcx = self.tcx;
|
||||||
|
if let Def::SelfCtor(impl_def_id) = def {
|
||||||
|
let ty = self.impl_self_ty(span, impl_def_id).ty;
|
||||||
|
let adt_def = ty.ty_adt_def();
|
||||||
|
|
||||||
|
match adt_def {
|
||||||
|
Some(adt_def) if adt_def.has_ctor() => {
|
||||||
|
let variant = adt_def.non_enum_variant();
|
||||||
|
let def = Def::StructCtor(variant.did, variant.ctor_kind);
|
||||||
|
(def, variant.did, tcx.type_of(variant.did))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut err = tcx.sess.struct_span_err(span,
|
||||||
|
"the `Self` constructor can only be used with tuple or unit structs");
|
||||||
|
if let Some(adt_def) = adt_def {
|
||||||
|
match adt_def.adt_kind() {
|
||||||
|
AdtKind::Enum => {
|
||||||
|
err.help("did you mean to use one of the enum's variants?");
|
||||||
|
},
|
||||||
|
AdtKind::Struct |
|
||||||
|
AdtKind::Union => {
|
||||||
|
err.span_suggestion(
|
||||||
|
span,
|
||||||
|
"use curly brackets",
|
||||||
|
String::from("Self { /* fields */ }"),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
|
||||||
|
(def, impl_def_id, tcx.types.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let def_id = def.def_id();
|
||||||
|
|
||||||
|
// The things we are substituting into the type should not contain
|
||||||
|
// escaping late-bound regions, and nor should the base type scheme.
|
||||||
|
let ty = tcx.type_of(def_id);
|
||||||
|
(def, def_id, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Instantiates the given path, which must refer to an item with the given
|
// Instantiates the given path, which must refer to an item with the given
|
||||||
// number of type parameters and type.
|
// number of type parameters and type.
|
||||||
pub fn instantiate_value_path(&self,
|
pub fn instantiate_value_path(&self,
|
||||||
@ -5321,6 +5368,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
match def {
|
||||||
|
Def::Local(nid) | Def::Upvar(nid, ..) => {
|
||||||
|
let hid = self.tcx.hir().node_to_hir_id(nid);
|
||||||
|
let ty = self.local_ty(span, hid).decl_ty;
|
||||||
|
let ty = self.normalize_associated_types_in(span, &ty);
|
||||||
|
self.write_ty(hir_id, ty);
|
||||||
|
return (ty, def);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (def, def_id, ty) = self.rewrite_self_ctor(def, span);
|
||||||
let path_segs = AstConv::def_ids_for_path_segments(self, segments, self_ty, def);
|
let path_segs = AstConv::def_ids_for_path_segments(self, segments, self_ty, def);
|
||||||
|
|
||||||
let mut user_self_ty = None;
|
let mut user_self_ty = None;
|
||||||
@ -5382,17 +5441,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
user_self_ty = None;
|
user_self_ty = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
match def {
|
|
||||||
Def::Local(nid) | Def::Upvar(nid, ..) => {
|
|
||||||
let hid = self.tcx.hir().node_to_hir_id(nid);
|
|
||||||
let ty = self.local_ty(span, hid).decl_ty;
|
|
||||||
let ty = self.normalize_associated_types_in(span, &ty);
|
|
||||||
self.write_ty(hir_id, ty);
|
|
||||||
return (ty, def);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we have to compare the types that the user *actually*
|
// Now we have to compare the types that the user *actually*
|
||||||
// provided against the types that were *expected*. If the user
|
// provided against the types that were *expected*. If the user
|
||||||
// did not provide any types, then we want to substitute inference
|
// did not provide any types, then we want to substitute inference
|
||||||
@ -5425,53 +5473,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
tcx.generics_of(*def_id).has_self
|
tcx.generics_of(*def_id).has_self
|
||||||
}).unwrap_or(false);
|
}).unwrap_or(false);
|
||||||
|
|
||||||
let mut new_def = def;
|
|
||||||
let (def_id, ty) = match def {
|
|
||||||
Def::SelfCtor(impl_def_id) => {
|
|
||||||
let ty = self.impl_self_ty(span, impl_def_id).ty;
|
|
||||||
let adt_def = ty.ty_adt_def();
|
|
||||||
|
|
||||||
match adt_def {
|
|
||||||
Some(adt_def) if adt_def.has_ctor() => {
|
|
||||||
let variant = adt_def.non_enum_variant();
|
|
||||||
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
|
|
||||||
(variant.did, tcx.type_of(variant.did))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mut err = tcx.sess.struct_span_err(span,
|
|
||||||
"the `Self` constructor can only be used with tuple or unit structs");
|
|
||||||
if let Some(adt_def) = adt_def {
|
|
||||||
match adt_def.adt_kind() {
|
|
||||||
AdtKind::Enum => {
|
|
||||||
err.help("did you mean to use one of the enum's variants?");
|
|
||||||
},
|
|
||||||
AdtKind::Struct |
|
|
||||||
AdtKind::Union => {
|
|
||||||
err.span_suggestion(
|
|
||||||
span,
|
|
||||||
"use curly brackets",
|
|
||||||
String::from("Self { /* fields */ }"),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
|
|
||||||
(impl_def_id, tcx.types.err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let def_id = def.def_id();
|
|
||||||
|
|
||||||
// The things we are substituting into the type should not contain
|
|
||||||
// escaping late-bound regions, and nor should the base type scheme.
|
|
||||||
let ty = tcx.type_of(def_id);
|
|
||||||
(def_id, ty)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let substs = AstConv::create_substs_for_generic_args(
|
let substs = AstConv::create_substs_for_generic_args(
|
||||||
tcx,
|
tcx,
|
||||||
def_id,
|
def_id,
|
||||||
@ -5587,7 +5588,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
ty_substituted);
|
ty_substituted);
|
||||||
self.write_substs(hir_id, substs);
|
self.write_substs(hir_id, substs);
|
||||||
|
|
||||||
(ty_substituted, new_def)
|
(ty_substituted, def)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_rustc_args_require_const(&self,
|
fn check_rustc_args_require_const(&self,
|
||||||
|
9
src/test/run-pass/issues/issue-57924.rs
Normal file
9
src/test/run-pass/issues/issue-57924.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub struct Gcm<E>(E);
|
||||||
|
|
||||||
|
impl<E> Gcm<E> {
|
||||||
|
pub fn crash(e: E) -> Self {
|
||||||
|
Self::<E>(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user