Skip to content

Commit c77fdbf

Browse files
author
Alexander Regueiro
committed
Implemented variants on type aliases in both ctor and pattern position.
1 parent 1b150c4 commit c77fdbf

File tree

6 files changed

+166
-35
lines changed

6 files changed

+166
-35
lines changed

src/librustc_mir/hair/cx/expr.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -481,10 +481,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
481481
}
482482
}
483483
AdtKind::Enum => {
484-
let def = match *qpath {
485-
hir::QPath::Resolved(_, ref path) => path.def,
486-
hir::QPath::TypeRelative(..) => Def::Err,
487-
};
484+
let def = cx.tables().qpath_def(qpath, expr.hir_id);
488485
match def {
489486
Def::Variant(variant_id) => {
490487
assert!(base.is_none());

src/librustc_typeck/astconv.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use std::collections::BTreeSet;
3131
use std::iter;
3232
use std::slice;
3333

34+
use super::{allow_type_alias_enum_variants};
35+
3436
pub trait AstConv<'gcx, 'tcx> {
3537
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
3638

@@ -1275,6 +1277,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
12751277
ref_id: ast::NodeId,
12761278
span: Span,
12771279
ty: Ty<'tcx>,
1280+
ty_hir: &hir::Ty,
12781281
ty_path_def: Def,
12791282
item_segment: &hir::PathSegment)
12801283
-> (Ty<'tcx>, Def)
@@ -1286,6 +1289,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
12861289

12871290
self.prohibit_generics(slice::from_ref(item_segment));
12881291

1292+
// Check if we have an enum variant here.
1293+
if let ty::Adt(adt_def, _) = ty.sty {
1294+
if adt_def.is_enum() {
1295+
if allow_type_alias_enum_variants(tcx, ty_hir, span) {
1296+
let variant_def = adt_def.variants.iter().find(|vd| {
1297+
tcx.hygienic_eq(assoc_name, vd.ident, adt_def.did)
1298+
});
1299+
if let Some(variant_def) = variant_def {
1300+
let def = Def::Variant(variant_def.did);
1301+
return (ty, def);
1302+
}
1303+
}
1304+
}
1305+
}
1306+
12891307
// Find the type of the associated item, and the trait where the associated
12901308
// item is declared.
12911309
let bound = match (&ty.sty, ty_path_def) {
@@ -1342,7 +1360,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
13421360
return (tcx.types.err, Def::Err);
13431361
}
13441362
_ => {
1345-
// Don't print TyErr to the user.
1363+
// Don't print `TyErr` to the user.
13461364
if !ty.references_error() {
13471365
self.report_ambiguous_associated_type(span,
13481366
&ty.to_string(),
@@ -1505,10 +1523,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
15051523
}
15061524
Def::SelfTy(_, Some(def_id)) => {
15071525
// `Self` in impl (we know the concrete type)
1508-
15091526
assert_eq!(opt_self_ty, None);
15101527
self.prohibit_generics(&path.segments);
1511-
15121528
tcx.at(span).type_of(def_id)
15131529
}
15141530
Def::SelfTy(Some(_), None) => {
@@ -1602,7 +1618,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
16021618
} else {
16031619
Def::Err
16041620
};
1605-
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
1621+
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, qself, def, segment).0
16061622
}
16071623
hir::TyKind::Array(ref ty, ref length) => {
16081624
let length_def_id = tcx.hir().local_def_id(length.id);

src/librustc_typeck/check/method/mod.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Method lookup: the secret sauce of Rust. See the [rustc guide] chapter.
1+
//! Method lookup: the secret sauce of Rust. See the [rustc guide] for more information.
22
//!
33
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/method-lookup.html
44
@@ -25,6 +25,7 @@ use rustc::infer::{self, InferOk};
2525
use syntax::ast;
2626
use syntax_pos::Span;
2727

28+
use crate::{allow_type_alias_enum_variants};
2829
use self::probe::{IsSuggestion, ProbeScope};
2930

3031
pub fn provide(providers: &mut ty::query::Providers) {
@@ -360,21 +361,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
360361
span: Span,
361362
method_name: ast::Ident,
362363
self_ty: Ty<'tcx>,
364+
self_ty_hir: &hir::Ty,
363365
expr_id: ast::NodeId)
364366
-> Result<Def, MethodError<'tcx>> {
367+
debug!("resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}",
368+
method_name,
369+
self_ty,
370+
expr_id
371+
);
372+
373+
let tcx = self.tcx;
374+
375+
// Check if we have an enum variant here.
376+
if let ty::Adt(adt_def, _) = self_ty.sty {
377+
if adt_def.is_enum() {
378+
if allow_type_alias_enum_variants(tcx, self_ty_hir, span) {
379+
let variant_def = adt_def.variants.iter().find(|vd| {
380+
tcx.hygienic_eq(method_name, vd.ident, adt_def.did)
381+
});
382+
if let Some(variant_def) = variant_def {
383+
let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind);
384+
return Ok(def);
385+
}
386+
}
387+
}
388+
}
389+
365390
let mode = probe::Mode::Path;
366391
let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
367392
self_ty, expr_id, ProbeScope::TraitsInScope)?;
368393

369394
if let Some(import_id) = pick.import_id {
370-
let import_def_id = self.tcx.hir().local_def_id(import_id);
371-
debug!("used_trait_import: {:?}", import_def_id);
395+
let import_def_id = tcx.hir().local_def_id(import_id);
396+
debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
372397
Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
373-
.unwrap().insert(import_def_id);
398+
.unwrap().insert(import_def_id);
374399
}
375400

376401
let def = pick.item.def();
377-
self.tcx.check_stability(def.def_id(), Some(expr_id), span);
402+
tcx.check_stability(def.def_id(), Some(expr_id), span);
378403

379404
Ok(def)
380405
}

src/librustc_typeck/check/mod.rs

Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ use rustc::infer::opaque_types::OpaqueTypeDecl;
101101
use rustc::infer::type_variable::{TypeVariableOrigin};
102102
use rustc::middle::region;
103103
use rustc::mir::interpret::{ConstValue, GlobalId};
104-
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
105-
UserSelfTy, UserSubsts};
106104
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
107105
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility,
108106
ToPolyTraitRef, ToPredicate};
109107
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
110108
use rustc::ty::fold::TypeFoldable;
111109
use rustc::ty::query::Providers;
110+
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
111+
UserSelfTy, UserSubsts};
112112
use rustc::ty::util::{Representability, IntTypeExt, Discr};
113113
use rustc::ty::layout::VariantIdx;
114114
use syntax_pos::{self, BytePos, Span, MultiSpan};
@@ -4539,7 +4539,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
45394539
Def::Err
45404540
};
45414541
let (ty, def) = AstConv::associated_path_def_to_ty(self, node_id, path_span,
4542-
ty, def, segment);
4542+
ty, qself, def, segment);
45434543

45444544
// Write back the new resolution.
45454545
let hir_id = self.tcx.hir().node_to_hir_id(node_id);
@@ -4558,14 +4558,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
45584558
span: Span)
45594559
-> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
45604560
{
4561-
let (ty, item_segment) = match *qpath {
4561+
let (ty, ty_hir, item_segment) = match *qpath {
45624562
hir::QPath::Resolved(ref opt_qself, ref path) => {
45634563
return (path.def,
45644564
opt_qself.as_ref().map(|qself| self.to_ty(qself)),
45654565
&path.segments[..]);
45664566
}
45674567
hir::QPath::TypeRelative(ref qself, ref segment) => {
4568-
(self.to_ty(qself), segment)
4568+
(self.to_ty(qself), qself, segment)
45694569
}
45704570
};
45714571
let hir_id = self.tcx.hir().node_to_hir_id(node_id);
@@ -4575,7 +4575,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
45754575
return (*cached_def, Some(ty), slice::from_ref(&**item_segment))
45764576
}
45774577
let item_name = item_segment.ident;
4578-
let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
4578+
let def = match self.resolve_ufcs(span, item_name, ty, ty_hir, node_id) {
45794579
Ok(def) => def,
45804580
Err(error) => {
45814581
let def = match error {
@@ -5042,6 +5042,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50425042

50435043
fn def_ids_for_path_segments(&self,
50445044
segments: &[hir::PathSegment],
5045+
self_ty: Option<Ty<'tcx>>,
50455046
def: Def)
50465047
-> Vec<PathSeg> {
50475048
// We need to extract the type parameters supplied by the user in
@@ -5053,15 +5054,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50535054
//
50545055
// There are basically four cases to consider:
50555056
//
5056-
// 1. Reference to a constructor of enum variant or struct:
5057+
// 1. Reference to a constructor of a struct:
50575058
//
50585059
// struct Foo<T>(...)
5060+
//
5061+
// In this case, the parameters are declared in the type space.
5062+
//
5063+
// 2. Reference to a constructor of an enum variant:
5064+
//
50595065
// enum E<T> { Foo(...) }
50605066
//
5061-
// In these cases, the parameters are declared in the type
5062-
// space.
5067+
// In this case, the parameters are defined in the type space,
5068+
// but may be specified either on the type or the variant.
50635069
//
5064-
// 2. Reference to a fn item or a free constant:
5070+
// 3. Reference to a fn item or a free constant:
50655071
//
50665072
// fn foo<T>() { }
50675073
//
@@ -5070,7 +5076,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50705076
// type parameters. However, in this case, those parameters are
50715077
// declared on a value, and hence are in the `FnSpace`.
50725078
//
5073-
// 3. Reference to a method or an associated constant:
5079+
// 4. Reference to a method or an associated constant:
50745080
//
50755081
// impl<A> SomeStruct<A> {
50765082
// fn foo<B>(...)
@@ -5082,7 +5088,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50825088
// `SomeStruct::<A>`, contains parameters in TypeSpace, and the
50835089
// final segment, `foo::<B>` contains parameters in fn space.
50845090
//
5085-
// 4. Reference to a local variable
5091+
// 5. Reference to a local variable
50865092
//
50875093
// Local variables can't have any type parameters.
50885094
//
@@ -5094,9 +5100,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50945100
let mut path_segs = vec![];
50955101

50965102
match def {
5097-
// Case 1. Reference to a struct/variant constructor.
5103+
// Case 1. Reference to a struct constructor.
50985104
Def::StructCtor(def_id, ..) |
5099-
Def::VariantCtor(def_id, ..) |
51005105
Def::SelfCtor(.., def_id) => {
51015106
// Everything but the final segment should have no
51025107
// parameters at all.
@@ -5107,14 +5112,49 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51075112
path_segs.push(PathSeg(generics_def_id, last));
51085113
}
51095114

5110-
// Case 2. Reference to a top-level value.
5115+
// Case 2. Reference to a variant constructor.
5116+
Def::VariantCtor(def_id, ..) => {
5117+
if tcx.features().type_alias_enum_variants {
5118+
let adt_def = self_ty.and_then(|t| t.ty_adt_def());
5119+
let (generics_def_id, index) = if let Some(adt_def) = adt_def {
5120+
debug_assert!(adt_def.is_enum());
5121+
(adt_def.did, last)
5122+
} else if last >= 1 && segments[last - 1].args.is_some() {
5123+
// Everything but the penultimate segment should have no
5124+
// parameters at all.
5125+
let enum_def_id = self.tcx.parent_def_id(def_id).unwrap();
5126+
(enum_def_id, last - 1)
5127+
} else {
5128+
// FIXME: lint here suggesting `Enum::<...>::Variant` form
5129+
// instead of `Enum::Variant::<...>` form.
5130+
5131+
// Everything but the final segment should have no
5132+
// parameters at all.
5133+
let generics = self.tcx.generics_of(def_id);
5134+
// Variant and struct constructors use the
5135+
// generics of their parent type definition.
5136+
(generics.parent.unwrap_or(def_id), last)
5137+
};
5138+
path_segs.push(PathSeg(generics_def_id, index));
5139+
} else {
5140+
// Everything but the final segment should have no
5141+
// parameters at all.
5142+
let generics = self.tcx.generics_of(def_id);
5143+
// Variant and struct constructors use the
5144+
// generics of their parent type definition.
5145+
let generics_def_id = generics.parent.unwrap_or(def_id);
5146+
path_segs.push(PathSeg(generics_def_id, last));
5147+
}
5148+
}
5149+
5150+
// Case 3. Reference to a top-level value.
51115151
Def::Fn(def_id) |
51125152
Def::Const(def_id) |
51135153
Def::Static(def_id, _) => {
51145154
path_segs.push(PathSeg(def_id, last));
51155155
}
51165156

5117-
// Case 3. Reference to a method or associated const.
5157+
// Case 4. Reference to a method or associated const.
51185158
Def::Method(def_id) |
51195159
Def::AssociatedConst(def_id) => {
51205160
if segments.len() >= 2 {
@@ -5124,7 +5164,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51245164
path_segs.push(PathSeg(def_id, last));
51255165
}
51265166

5127-
// Case 4. Local variable, no generics.
5167+
// Case 5. Local variable, no generics.
51285168
Def::Local(..) | Def::Upvar(..) => {}
51295169

51305170
_ => bug!("unexpected definition: {:?}", def),
@@ -5152,7 +5192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51525192
node_id,
51535193
);
51545194

5155-
let path_segs = self.def_ids_for_path_segments(segments, def);
5195+
let path_segs = self.def_ids_for_path_segments(segments, self_ty, def);
51565196

51575197
let mut user_self_ty = None;
51585198
match def {
@@ -5187,10 +5227,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51875227
// provided (if any) into their appropriate spaces. We'll also report
51885228
// errors if type parameters are provided in an inappropriate place.
51895229

5190-
let generic_segs = path_segs.iter().map(|PathSeg(_, index)| index)
5191-
.collect::<FxHashSet<_>>();
5230+
let is_alias_variant_ctor = if tcx.features().type_alias_enum_variants {
5231+
match def {
5232+
Def::VariantCtor(_, _) if self_ty.is_some() => true,
5233+
_ => false,
5234+
};
5235+
} else {
5236+
false
5237+
};
5238+
5239+
let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
51925240
AstConv::prohibit_generics(self, segments.iter().enumerate().filter_map(|(index, seg)| {
5193-
if !generic_segs.contains(&index) {
5241+
if !generic_segs.contains(&index) || is_alias_variant_ctor {
51945242
Some(seg)
51955243
} else {
51965244
None
@@ -5274,6 +5322,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
52745322
}
52755323
}
52765324
}
5325+
Def::VariantCtor(_, _) if self_ty.is_some() => {
5326+
let def_id = def.def_id();
5327+
5328+
let ty = self.tcx.type_of(def_id);
5329+
if tcx.features().type_alias_enum_variants {
5330+
if let Some(self_ty) = self_ty {
5331+
match ty.ty_adt_def() {
5332+
Some(adt_def) if adt_def.is_enum() => {
5333+
return (self_ty, def);
5334+
}
5335+
_ => {}
5336+
}
5337+
}
5338+
}
5339+
(def_id, ty)
5340+
}
52775341
_ => {
52785342
let def_id = def.def_id();
52795343

0 commit comments

Comments
 (0)