Rewrite check_pat_enum, split it into check_pat_tuple_struct and check_pat_path
Update definitions in def_map for associated types written in unqualified form (like `Self::Output`) Cleanup finish_resolving_def_to_ty/resolve_ty_and_def_ufcs Make VariantDef's available through constructor IDs
This commit is contained in:
parent
eb32440d45
commit
2cdd9f1c97
|
@ -137,15 +137,6 @@ impl Def {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
|
|
||||||
match *self {
|
|
||||||
Def::Variant(enum_id, var_id) => {
|
|
||||||
Some((enum_id, var_id))
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind_name(&self) -> &'static str {
|
pub fn kind_name(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
Def::Fn(..) => "function",
|
Def::Fn(..) => "function",
|
||||||
|
|
|
@ -12,15 +12,12 @@ use hir::def::*;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::{self, PatKind};
|
use hir::{self, PatKind};
|
||||||
use ty::TyCtxt;
|
use ty::TyCtxt;
|
||||||
use util::nodemap::FnvHashMap;
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::Spanned;
|
use syntax::codemap::Spanned;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
|
||||||
use std::iter::{Enumerate, ExactSizeIterator};
|
use std::iter::{Enumerate, ExactSizeIterator};
|
||||||
|
|
||||||
pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
|
|
||||||
|
|
||||||
pub struct EnumerateAndAdjust<I> {
|
pub struct EnumerateAndAdjust<I> {
|
||||||
enumerate: Enumerate<I>,
|
enumerate: Enumerate<I>,
|
||||||
gap_pos: usize,
|
gap_pos: usize,
|
||||||
|
@ -97,22 +94,6 @@ pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as above, except that partially-resolved defs cause `false` to be
|
|
||||||
// returned instead of a panic.
|
|
||||||
pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool {
|
|
||||||
match pat.node {
|
|
||||||
PatKind::Path(..) | PatKind::QPath(..) => {
|
|
||||||
match dm.get(&pat.id)
|
|
||||||
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
|
|
||||||
else { None } ) {
|
|
||||||
Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||||
/// `match foo() { Some(a) => (), None => () }`
|
/// `match foo() { Some(a) => (), None => () }`
|
||||||
pub fn pat_bindings<F>(pat: &hir::Pat, mut f: F)
|
pub fn pat_bindings<F>(pat: &hir::Pat, mut f: F)
|
||||||
|
|
|
@ -591,6 +591,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.global_interners.arenas.trait_defs.alloc(def)
|
self.global_interners.arenas.trait_defs.alloc(def)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_adt_def(self, did: DefId, adt_def: ty::AdtDefMaster<'gcx>) {
|
||||||
|
// this will need a transmute when reverse-variance is removed
|
||||||
|
if let Some(prev) = self.adt_defs.borrow_mut().insert(did, adt_def) {
|
||||||
|
bug!("Tried to overwrite interned AdtDef: {:?}", prev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn intern_adt_def(self,
|
pub fn intern_adt_def(self,
|
||||||
did: DefId,
|
did: DefId,
|
||||||
kind: ty::AdtKind,
|
kind: ty::AdtKind,
|
||||||
|
@ -598,10 +605,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
-> ty::AdtDefMaster<'gcx> {
|
-> ty::AdtDefMaster<'gcx> {
|
||||||
let def = ty::AdtDefData::new(self, did, kind, variants);
|
let def = ty::AdtDefData::new(self, did, kind, variants);
|
||||||
let interned = self.global_interners.arenas.adt_defs.alloc(def);
|
let interned = self.global_interners.arenas.adt_defs.alloc(def);
|
||||||
// this will need a transmute when reverse-variance is removed
|
self.insert_adt_def(did, interned);
|
||||||
if let Some(prev) = self.adt_defs.borrow_mut().insert(did, interned) {
|
|
||||||
bug!("Tried to overwrite interned AdtDef: {:?}", prev)
|
|
||||||
}
|
|
||||||
interned
|
interned
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2454,6 +2454,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.def_map.borrow().get(&id).map(|resolution| resolution.full_def())
|
self.def_map.borrow().get(&id).map(|resolution| resolution.full_def())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns `ty::VariantDef` if `def` refers to a struct,
|
||||||
|
// or variant or their constructors, panics otherwise.
|
||||||
|
pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> {
|
||||||
|
match def {
|
||||||
|
Def::Variant(enum_did, did) => {
|
||||||
|
self.lookup_adt_def(enum_did).variant_with_id(did)
|
||||||
|
}
|
||||||
|
Def::Struct(did) => {
|
||||||
|
self.lookup_adt_def(did).struct_variant()
|
||||||
|
}
|
||||||
|
_ => bug!("expect_variant_def used with unexpected def {:?}", def)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn def_key(self, id: DefId) -> ast_map::DefKey {
|
pub fn def_key(self, id: DefId) -> ast_map::DefKey {
|
||||||
if id.is_local() {
|
if id.is_local() {
|
||||||
self.map.def_key(id)
|
self.map.def_key(id)
|
||||||
|
|
|
@ -471,23 +471,29 @@ pub fn get_adt_def<'a, 'tcx>(intr: &IdentInterner,
|
||||||
|
|
||||||
let doc = cdata.lookup_item(item_id);
|
let doc = cdata.lookup_item(item_id);
|
||||||
let did = DefId { krate: cdata.cnum, index: item_id };
|
let did = DefId { krate: cdata.cnum, index: item_id };
|
||||||
|
let mut ctor_did = None;
|
||||||
let (kind, variants) = match item_family(doc) {
|
let (kind, variants) = match item_family(doc) {
|
||||||
Enum => {
|
Enum => {
|
||||||
(ty::AdtKind::Enum,
|
(ty::AdtKind::Enum,
|
||||||
get_enum_variants(intr, cdata, doc))
|
get_enum_variants(intr, cdata, doc))
|
||||||
}
|
}
|
||||||
Struct(..) => {
|
Struct(..) => {
|
||||||
let ctor_did =
|
// Use separate constructor id for unit/tuple structs and reuse did for braced structs.
|
||||||
reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
|
ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| {
|
||||||
map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
|
translated_def_id(cdata, ctor_doc)
|
||||||
|
});
|
||||||
(ty::AdtKind::Struct,
|
(ty::AdtKind::Struct,
|
||||||
vec![get_struct_variant(intr, cdata, doc, ctor_did)])
|
vec![get_struct_variant(intr, cdata, doc, ctor_did.unwrap_or(did))])
|
||||||
}
|
}
|
||||||
_ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
|
_ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
|
||||||
item_family(doc), did)
|
item_family(doc), did)
|
||||||
};
|
};
|
||||||
|
|
||||||
let adt = tcx.intern_adt_def(did, kind, variants);
|
let adt = tcx.intern_adt_def(did, kind, variants);
|
||||||
|
if let Some(ctor_did) = ctor_did {
|
||||||
|
// Make adt definition available through constructor id as well.
|
||||||
|
tcx.insert_adt_def(ctor_did, adt);
|
||||||
|
}
|
||||||
|
|
||||||
// this needs to be done *after* the variant is interned,
|
// this needs to be done *after* the variant is interned,
|
||||||
// to support recursive structures
|
// to support recursive structures
|
||||||
|
|
|
@ -53,7 +53,7 @@ use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
|
||||||
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
||||||
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
|
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
|
||||||
use hir::{self, SelfKind};
|
use hir::{self, SelfKind};
|
||||||
use hir::def::{self, Def};
|
use hir::def::{Def, PathResolution};
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::print as pprust;
|
use hir::print as pprust;
|
||||||
use middle::resolve_lifetime as rl;
|
use middle::resolve_lifetime as rl;
|
||||||
|
@ -1327,7 +1327,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.ensure_super_predicates(span, trait_did).is_err() {
|
if self.ensure_super_predicates(span, trait_did).is_err() {
|
||||||
return (tcx.types.err, ty_path_def);
|
return (tcx.types.err, Def::Err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let candidates: Vec<ty::PolyTraitRef> =
|
let candidates: Vec<ty::PolyTraitRef> =
|
||||||
|
@ -1341,7 +1341,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
&assoc_name.as_str(),
|
&assoc_name.as_str(),
|
||||||
span) {
|
span) {
|
||||||
Ok(bound) => bound,
|
Ok(bound) => bound,
|
||||||
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
|
Err(ErrorReported) => return (tcx.types.err, Def::Err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
|
(&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
|
||||||
|
@ -1351,7 +1351,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
assoc_name,
|
assoc_name,
|
||||||
span) {
|
span) {
|
||||||
Ok(bound) => bound,
|
Ok(bound) => bound,
|
||||||
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
|
Err(ErrorReported) => return (tcx.types.err, Def::Err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
|
(&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
|
||||||
|
@ -1361,7 +1361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
assoc_name,
|
assoc_name,
|
||||||
span) {
|
span) {
|
||||||
Ok(bound) => bound,
|
Ok(bound) => bound,
|
||||||
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
|
Err(ErrorReported) => return (tcx.types.err, Def::Err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1369,7 +1369,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
&ty.to_string(),
|
&ty.to_string(),
|
||||||
"Trait",
|
"Trait",
|
||||||
&assoc_name.as_str());
|
&assoc_name.as_str());
|
||||||
return (tcx.types.err, ty_path_def);
|
return (tcx.types.err, Def::Err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1574,45 +1574,46 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that both base_segments and assoc_segments may be empty, although not at
|
// Resolve possibly associated type path into a type and final definition.
|
||||||
// the same time.
|
// Note that both base_segments and assoc_segments may be empty, although not at same time.
|
||||||
pub fn finish_resolving_def_to_ty(&self,
|
pub fn finish_resolving_def_to_ty(&self,
|
||||||
rscope: &RegionScope,
|
rscope: &RegionScope,
|
||||||
span: Span,
|
span: Span,
|
||||||
param_mode: PathParamMode,
|
param_mode: PathParamMode,
|
||||||
mut def: Def,
|
base_def: Def,
|
||||||
opt_self_ty: Option<Ty<'tcx>>,
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
base_path_ref_id: ast::NodeId,
|
base_path_ref_id: ast::NodeId,
|
||||||
base_segments: &[hir::PathSegment],
|
base_segments: &[hir::PathSegment],
|
||||||
assoc_segments: &[hir::PathSegment])
|
assoc_segments: &[hir::PathSegment])
|
||||||
-> (Ty<'tcx>, Def) {
|
-> (Ty<'tcx>, Def) {
|
||||||
debug!("finish_resolving_def_to_ty(def={:?}, \
|
// Convert the base type.
|
||||||
|
debug!("finish_resolving_def_to_ty(base_def={:?}, \
|
||||||
base_segments={:?}, \
|
base_segments={:?}, \
|
||||||
assoc_segments={:?})",
|
assoc_segments={:?})",
|
||||||
def,
|
base_def,
|
||||||
base_segments,
|
base_segments,
|
||||||
assoc_segments);
|
assoc_segments);
|
||||||
let mut ty = self.base_def_to_ty(rscope,
|
let base_ty = self.base_def_to_ty(rscope,
|
||||||
span,
|
span,
|
||||||
param_mode,
|
param_mode,
|
||||||
def,
|
base_def,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
base_path_ref_id,
|
base_path_ref_id,
|
||||||
base_segments);
|
base_segments);
|
||||||
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
|
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty);
|
||||||
|
|
||||||
// If any associated type segments remain, attempt to resolve them.
|
// If any associated type segments remain, attempt to resolve them.
|
||||||
|
let (mut ty, mut def) = (base_ty, base_def);
|
||||||
for segment in assoc_segments {
|
for segment in assoc_segments {
|
||||||
debug!("finish_resolving_def_to_ty: segment={:?}", segment);
|
debug!("finish_resolving_def_to_ty: segment={:?}", segment);
|
||||||
if ty.sty == ty::TyError {
|
// This is pretty bad (it will fail except for T::A and Self::A).
|
||||||
|
let (new_ty, new_def) = self.associated_path_def_to_ty(span, ty, def, segment);
|
||||||
|
ty = new_ty;
|
||||||
|
def = new_def;
|
||||||
|
|
||||||
|
if def == Def::Err {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// This is pretty bad (it will fail except for T::A and Self::A).
|
|
||||||
let (a_ty, a_def) = self.associated_path_def_to_ty(span,
|
|
||||||
ty,
|
|
||||||
def,
|
|
||||||
segment);
|
|
||||||
ty = a_ty;
|
|
||||||
def = a_def;
|
|
||||||
}
|
}
|
||||||
(ty, def)
|
(ty, def)
|
||||||
}
|
}
|
||||||
|
@ -1719,23 +1720,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||||
hir::TyPath(ref maybe_qself, ref path) => {
|
hir::TyPath(ref maybe_qself, ref path) => {
|
||||||
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
|
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
|
||||||
let path_res = tcx.expect_resolution(ast_ty.id);
|
let path_res = tcx.expect_resolution(ast_ty.id);
|
||||||
let def = path_res.base_def;
|
|
||||||
let base_ty_end = path.segments.len() - path_res.depth;
|
let base_ty_end = path.segments.len() - path_res.depth;
|
||||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
|
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
|
||||||
self.ast_ty_to_ty(rscope, &qself.ty)
|
self.ast_ty_to_ty(rscope, &qself.ty)
|
||||||
});
|
});
|
||||||
let (ty, _def) = self.finish_resolving_def_to_ty(rscope,
|
let (ty, def) = self.finish_resolving_def_to_ty(rscope,
|
||||||
ast_ty.span,
|
ast_ty.span,
|
||||||
PathParamMode::Explicit,
|
PathParamMode::Explicit,
|
||||||
def,
|
path_res.base_def,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
ast_ty.id,
|
ast_ty.id,
|
||||||
&path.segments[..base_ty_end],
|
&path.segments[..base_ty_end],
|
||||||
&path.segments[base_ty_end..]);
|
&path.segments[base_ty_end..]);
|
||||||
|
|
||||||
if path_res.depth != 0 && ty.sty != ty::TyError {
|
// Write back the new resolution.
|
||||||
// Write back the new resolution.
|
if path_res.depth != 0 {
|
||||||
tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution::new(def));
|
tcx.def_map.borrow_mut().insert(ast_ty.id, PathResolution::new(def));
|
||||||
}
|
}
|
||||||
|
|
||||||
ty
|
ty
|
||||||
|
|
|
@ -10,13 +10,12 @@
|
||||||
|
|
||||||
use hir::def::Def;
|
use hir::def::Def;
|
||||||
use rustc::infer::{self, InferOk, TypeOrigin};
|
use rustc::infer::{self, InferOk, TypeOrigin};
|
||||||
use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
|
use hir::pat_util::EnumerateAndAdjustIterator;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
|
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
|
||||||
use check::{FnCtxt, Expectation};
|
use check::{FnCtxt, Expectation};
|
||||||
use lint;
|
use lint;
|
||||||
use util::nodemap::FnvHashMap;
|
use util::nodemap::FnvHashMap;
|
||||||
use session::Session;
|
|
||||||
|
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -28,20 +27,6 @@ use syntax_pos::Span;
|
||||||
use rustc::hir::{self, PatKind};
|
use rustc::hir::{self, PatKind};
|
||||||
use rustc::hir::print as pprust;
|
use rustc::hir::print as pprust;
|
||||||
|
|
||||||
// This function exists due to the warning "diagnostic code E0164 already used"
|
|
||||||
fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
|
|
||||||
let name = pprust::path_to_string(path);
|
|
||||||
let msg = format!("`{}` does not name a tuple variant or a tuple struct", name);
|
|
||||||
if lint {
|
|
||||||
sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
|
|
||||||
pat.id,
|
|
||||||
pat.span,
|
|
||||||
msg);
|
|
||||||
} else {
|
|
||||||
span_err!(sess, pat.span, E0164, "{}", msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
|
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
@ -136,22 +121,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// subtyping doesn't matter here, as the value is some kind of scalar
|
// subtyping doesn't matter here, as the value is some kind of scalar
|
||||||
self.demand_eqtype(pat.span, expected, lhs_ty);
|
self.demand_eqtype(pat.span, expected, lhs_ty);
|
||||||
}
|
}
|
||||||
PatKind::Path(..) if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
|
|
||||||
let const_did = tcx.expect_def(pat.id).def_id();
|
|
||||||
let const_scheme = tcx.lookup_item_type(const_did);
|
|
||||||
assert!(const_scheme.generics.is_empty());
|
|
||||||
let const_ty = self.instantiate_type_scheme(pat.span,
|
|
||||||
&Substs::empty(),
|
|
||||||
&const_scheme.ty);
|
|
||||||
self.write_ty(pat.id, const_ty);
|
|
||||||
|
|
||||||
// FIXME(#20489) -- we should limit the types here to scalars or something!
|
|
||||||
|
|
||||||
// As with PatKind::Lit, what we really want here is that there
|
|
||||||
// exist a LUB, but for the cases that can occur, subtype
|
|
||||||
// is good enough.
|
|
||||||
self.demand_suptype(pat.span, expected, const_ty);
|
|
||||||
}
|
|
||||||
PatKind::Binding(bm, _, ref sub) => {
|
PatKind::Binding(bm, _, ref sub) => {
|
||||||
let typ = self.local_ty(pat.span, pat.id);
|
let typ = self.local_ty(pat.span, pat.id);
|
||||||
match bm {
|
match bm {
|
||||||
|
@ -197,33 +166,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
|
PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
|
||||||
self.check_pat_enum(pat, path, &subpats, ddpos, expected, true);
|
self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
|
||||||
}
|
}
|
||||||
PatKind::Path(ref path) => {
|
PatKind::Path(ref path) => {
|
||||||
self.check_pat_enum(pat, path, &[], None, expected, false);
|
self.check_pat_path(pat, None, path, expected);
|
||||||
}
|
}
|
||||||
PatKind::QPath(ref qself, ref path) => {
|
PatKind::QPath(ref qself, ref path) => {
|
||||||
let self_ty = self.to_ty(&qself.ty);
|
self.check_pat_path(pat, Some(self.to_ty(&qself.ty)), path, expected);
|
||||||
let path_res = tcx.expect_resolution(pat.id);
|
|
||||||
if path_res.base_def == Def::Err {
|
|
||||||
self.set_tainted_by_errors();
|
|
||||||
self.write_error(pat.id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if let Some((opt_ty, segments, def)) =
|
|
||||||
self.resolve_ty_and_def_ufcs(path_res, Some(self_ty),
|
|
||||||
path, pat.span, pat.id) {
|
|
||||||
if self.check_assoc_item_is_const(def, pat.span) {
|
|
||||||
let scheme = tcx.lookup_item_type(def.def_id());
|
|
||||||
let predicates = tcx.lookup_predicates(def.def_id());
|
|
||||||
self.instantiate_path(segments, scheme, &predicates,
|
|
||||||
opt_ty, def, pat.span, pat.id);
|
|
||||||
let const_ty = self.node_ty(pat.id);
|
|
||||||
self.demand_suptype(pat.span, expected, const_ty);
|
|
||||||
} else {
|
|
||||||
self.write_error(pat.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PatKind::Struct(ref path, ref fields, etc) => {
|
PatKind::Struct(ref path, ref fields, etc) => {
|
||||||
self.check_pat_struct(pat, path, fields, etc, expected);
|
self.check_pat_struct(pat, path, fields, etc, expected);
|
||||||
|
@ -403,20 +352,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
// subtyping.
|
// subtyping.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
|
|
||||||
match def {
|
|
||||||
Def::AssociatedConst(..) => true,
|
|
||||||
Def::Method(..) => {
|
|
||||||
span_err!(self.tcx.sess, span, E0327,
|
|
||||||
"associated items in match patterns must be constants");
|
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
span_bug!(span, "non-associated item in check_assoc_item_is_const");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
|
pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
|
||||||
if let PatKind::Binding(..) = inner.node {
|
if let PatKind::Binding(..) = inner.node {
|
||||||
if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
|
if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
|
||||||
|
@ -589,132 +524,137 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_pat_enum(&self,
|
fn check_pat_path(&self,
|
||||||
pat: &hir::Pat,
|
pat: &hir::Pat,
|
||||||
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
path: &hir::Path,
|
path: &hir::Path,
|
||||||
subpats: &'gcx [P<hir::Pat>],
|
expected: Ty<'tcx>)
|
||||||
ddpos: Option<usize>,
|
|
||||||
expected: Ty<'tcx>,
|
|
||||||
is_tuple_struct_pat: bool)
|
|
||||||
{
|
{
|
||||||
// Typecheck the path.
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
let report_unexpected_def = || {
|
||||||
let path_res = tcx.expect_resolution(pat.id);
|
span_err!(tcx.sess, pat.span, E0533,
|
||||||
if path_res.base_def == Def::Err {
|
"`{}` does not name a unit variant, unit struct or a constant",
|
||||||
self.set_tainted_by_errors();
|
pprust::path_to_string(path));
|
||||||
self.write_error(pat.id);
|
self.write_error(pat.id);
|
||||||
|
|
||||||
for pat in subpats {
|
|
||||||
self.check_pat(&pat, tcx.types.err);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res,
|
|
||||||
None, path,
|
|
||||||
pat.span, pat.id) {
|
|
||||||
Some(resolution) => resolution,
|
|
||||||
// Error handling done inside resolve_ty_and_def_ufcs, so if
|
|
||||||
// resolution fails just return.
|
|
||||||
None => {return;}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Items that were partially resolved before should have been resolved to
|
// Resolve the path and check the definition for errors.
|
||||||
// associated constants (i.e. not methods).
|
let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(pat.id),
|
||||||
if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) {
|
opt_self_ty, path, pat.span, pat.id);
|
||||||
self.write_error(pat.id);
|
match def {
|
||||||
return;
|
Def::Err => {
|
||||||
|
self.set_tainted_by_errors();
|
||||||
|
self.write_error(pat.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Def::Method(..) => {
|
||||||
|
report_unexpected_def();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Def::Variant(..) | Def::Struct(..) => {
|
||||||
|
let variant = tcx.expect_variant_def(def);
|
||||||
|
if variant.kind != VariantKind::Unit {
|
||||||
|
report_unexpected_def();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Def::Const(..) | Def::AssociatedConst(..) => {} // OK
|
||||||
|
_ => bug!("unexpected pattern definition {:?}", def)
|
||||||
}
|
}
|
||||||
|
|
||||||
let enum_def = def.variant_def_ids()
|
// Type check the path.
|
||||||
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
|
let scheme = tcx.lookup_item_type(def.def_id());
|
||||||
|
let predicates = tcx.lookup_predicates(def.def_id());
|
||||||
|
self.instantiate_path(segments, scheme, &predicates, opt_ty, def, pat.span, pat.id);
|
||||||
|
let pat_ty = self.node_ty(pat.id);
|
||||||
|
self.demand_suptype(pat.span, expected, pat_ty);
|
||||||
|
}
|
||||||
|
|
||||||
let ctor_scheme = tcx.lookup_item_type(enum_def);
|
fn check_pat_tuple_struct(&self,
|
||||||
let ctor_predicates = tcx.lookup_predicates(enum_def);
|
pat: &hir::Pat,
|
||||||
let path_scheme = if ctor_scheme.ty.is_fn() {
|
path: &hir::Path,
|
||||||
let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap();
|
subpats: &'gcx [P<hir::Pat>],
|
||||||
ty::TypeScheme {
|
ddpos: Option<usize>,
|
||||||
ty: fn_ret.unwrap(),
|
expected: Ty<'tcx>)
|
||||||
generics: ctor_scheme.generics,
|
{
|
||||||
}
|
let tcx = self.tcx;
|
||||||
} else {
|
let on_error = || {
|
||||||
ctor_scheme
|
|
||||||
};
|
|
||||||
self.instantiate_path(segments, path_scheme, &ctor_predicates,
|
|
||||||
opt_ty, def, pat.span, pat.id);
|
|
||||||
let report_bad_struct_kind = |is_warning| {
|
|
||||||
bad_struct_kind_err(tcx.sess, pat, path, is_warning);
|
|
||||||
if is_warning { return; }
|
|
||||||
self.write_error(pat.id);
|
self.write_error(pat.id);
|
||||||
for pat in subpats {
|
for pat in subpats {
|
||||||
self.check_pat(&pat, tcx.types.err);
|
self.check_pat(&pat, tcx.types.err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let report_unexpected_def = |is_lint| {
|
||||||
// If we didn't have a fully resolved path to start with, we had an
|
let msg = format!("`{}` does not name a tuple variant or a tuple struct",
|
||||||
// associated const, and we should quit now, since the rest of this
|
pprust::path_to_string(path));
|
||||||
// function uses checks specific to structs and enums.
|
if is_lint {
|
||||||
if path_res.depth != 0 {
|
tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
|
||||||
if is_tuple_struct_pat {
|
pat.id, pat.span, msg);
|
||||||
report_bad_struct_kind(false);
|
|
||||||
} else {
|
} else {
|
||||||
let pat_ty = self.node_ty(pat.id);
|
span_err!(tcx.sess, pat.span, E0164, "{}", msg);
|
||||||
self.demand_suptype(pat.span, expected, pat_ty);
|
on_error();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolve the path and check the definition for errors.
|
||||||
|
let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(pat.id),
|
||||||
|
None, path, pat.span, pat.id);
|
||||||
|
match def {
|
||||||
|
Def::Err => {
|
||||||
|
self.set_tainted_by_errors();
|
||||||
|
on_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
|
||||||
|
report_unexpected_def(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Def::Variant(..) | Def::Struct(..) => {} // OK
|
||||||
|
_ => bug!("unexpected pattern definition {:?}", def)
|
||||||
|
}
|
||||||
|
let variant = tcx.expect_variant_def(def);
|
||||||
|
if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() {
|
||||||
|
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
|
||||||
|
// is allowed for backward compatibility.
|
||||||
|
report_unexpected_def(true);
|
||||||
|
} else if variant.kind != VariantKind::Tuple {
|
||||||
|
report_unexpected_def(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Type check the path.
|
||||||
|
let scheme = tcx.lookup_item_type(def.def_id());
|
||||||
|
let scheme = if scheme.ty.is_fn() {
|
||||||
|
// Replace constructor type with constructed type for tuple struct patterns.
|
||||||
|
let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap().unwrap();
|
||||||
|
ty::TypeScheme { ty: fn_ret, generics: scheme.generics }
|
||||||
|
} else {
|
||||||
|
// Leave the type as is for unit structs (backward compatibility).
|
||||||
|
scheme
|
||||||
|
};
|
||||||
|
let predicates = tcx.lookup_predicates(def.def_id());
|
||||||
|
self.instantiate_path(segments, scheme, &predicates, opt_ty, def, pat.span, pat.id);
|
||||||
let pat_ty = self.node_ty(pat.id);
|
let pat_ty = self.node_ty(pat.id);
|
||||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
self.demand_eqtype(pat.span, expected, pat_ty);
|
||||||
|
|
||||||
let real_path_ty = self.node_ty(pat.id);
|
// Type check subpatterns.
|
||||||
let (kind_name, variant, expected_substs) = match real_path_ty.sty {
|
|
||||||
ty::TyEnum(enum_def, expected_substs) => {
|
|
||||||
let variant = enum_def.variant_of_def(def);
|
|
||||||
("variant", variant, expected_substs)
|
|
||||||
}
|
|
||||||
ty::TyStruct(struct_def, expected_substs) => {
|
|
||||||
let variant = struct_def.struct_variant();
|
|
||||||
("struct", variant, expected_substs)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
report_bad_struct_kind(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match (is_tuple_struct_pat, variant.kind()) {
|
|
||||||
(true, ty::VariantKind::Unit) if subpats.is_empty() && ddpos.is_some() => {
|
|
||||||
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
|
|
||||||
// is allowed for backward compatibility.
|
|
||||||
report_bad_struct_kind(true);
|
|
||||||
}
|
|
||||||
(true, ty::VariantKind::Unit) |
|
|
||||||
(false, ty::VariantKind::Tuple) |
|
|
||||||
(_, ty::VariantKind::Struct) => {
|
|
||||||
report_bad_struct_kind(false);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if subpats.len() == variant.fields.len() ||
|
if subpats.len() == variant.fields.len() ||
|
||||||
subpats.len() < variant.fields.len() && ddpos.is_some() {
|
subpats.len() < variant.fields.len() && ddpos.is_some() {
|
||||||
|
let expected_substs = match pat_ty.sty {
|
||||||
|
ty::TyEnum(_, expected_substs) => expected_substs,
|
||||||
|
ty::TyStruct(_, expected_substs) => expected_substs,
|
||||||
|
ref ty => bug!("unexpected pattern type {:?}", ty),
|
||||||
|
};
|
||||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
|
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
|
||||||
let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs);
|
let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs);
|
||||||
self.check_pat(&subpat, field_ty);
|
self.check_pat(&subpat, field_ty);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
span_err!(tcx.sess, pat.span, E0023,
|
span_err!(tcx.sess, pat.span, E0023,
|
||||||
"this pattern has {} field{}, but the corresponding {} has {} field{}",
|
"this pattern has {} field{s}, but the corresponding {} has {} field{s}",
|
||||||
subpats.len(), if subpats.len() == 1 {""} else {"s"},
|
subpats.len(), def.kind_name(), variant.fields.len(),
|
||||||
kind_name,
|
s = if variant.fields.len() == 1 {""} else {"s"});
|
||||||
variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"});
|
on_error();
|
||||||
|
|
||||||
for pat in subpats {
|
|
||||||
self.check_pat(&pat, tcx.types.err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ use astconv::{AstConv, ast_region_to_region, PathParamMode};
|
||||||
use dep_graph::DepNode;
|
use dep_graph::DepNode;
|
||||||
use fmt_macros::{Parser, Piece, Position};
|
use fmt_macros::{Parser, Piece, Position};
|
||||||
use middle::cstore::LOCAL_CRATE;
|
use middle::cstore::LOCAL_CRATE;
|
||||||
use hir::def::{self, Def};
|
use hir::def::{Def, PathResolution};
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use hir::pat_util;
|
use hir::pat_util;
|
||||||
use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
|
use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
|
||||||
|
@ -3349,24 +3349,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
};
|
};
|
||||||
self.write_ty(id, oprnd_t);
|
self.write_ty(id, oprnd_t);
|
||||||
}
|
}
|
||||||
hir::ExprPath(ref maybe_qself, ref path) => {
|
hir::ExprPath(ref opt_qself, ref path) => {
|
||||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
|
let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
|
||||||
self.to_ty(&qself.ty)
|
let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(tcx.expect_resolution(id),
|
||||||
});
|
opt_self_ty, path, expr.span, expr.id);
|
||||||
|
if def != Def::Err {
|
||||||
let path_res = tcx.expect_resolution(id);
|
let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
|
||||||
if let Some((opt_ty, segments, def)) =
|
def);
|
||||||
self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path,
|
self.instantiate_path(segments, scheme, &predicates, opt_ty, def, expr.span, id);
|
||||||
expr.span, expr.id) {
|
} else {
|
||||||
if def != Def::Err {
|
self.set_tainted_by_errors();
|
||||||
let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
|
self.write_error(id);
|
||||||
def);
|
|
||||||
self.instantiate_path(segments, scheme, &predicates,
|
|
||||||
opt_ty, def, expr.span, id);
|
|
||||||
} else {
|
|
||||||
self.set_tainted_by_errors();
|
|
||||||
self.write_ty(id, self.tcx.types.err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We always require that the type provided as the value for
|
// We always require that the type provided as the value for
|
||||||
|
@ -3704,37 +3697,40 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
expected);
|
expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve associated value path into a base type and associated constant or method definition.
|
||||||
|
// The newly resolved definition is written into `def_map`.
|
||||||
pub fn resolve_ty_and_def_ufcs<'b>(&self,
|
pub fn resolve_ty_and_def_ufcs<'b>(&self,
|
||||||
path_res: def::PathResolution,
|
path_res: PathResolution,
|
||||||
opt_self_ty: Option<Ty<'tcx>>,
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
path: &'b hir::Path,
|
path: &'b hir::Path,
|
||||||
span: Span,
|
span: Span,
|
||||||
node_id: ast::NodeId)
|
node_id: ast::NodeId)
|
||||||
-> Option<(Option<Ty<'tcx>>, &'b [hir::PathSegment], Def)>
|
-> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
|
||||||
{
|
{
|
||||||
|
|
||||||
// If fully resolved already, we don't have to do anything.
|
// If fully resolved already, we don't have to do anything.
|
||||||
if path_res.depth == 0 {
|
if path_res.depth == 0 {
|
||||||
Some((opt_self_ty, &path.segments, path_res.base_def))
|
(path_res.base_def, opt_self_ty, &path.segments)
|
||||||
} else {
|
} else {
|
||||||
let def = path_res.base_def;
|
// Try to resolve everything except for the last segment as a type.
|
||||||
let ty_segments = path.segments.split_last().unwrap().1;
|
let ty_segments = path.segments.split_last().unwrap().1;
|
||||||
let base_ty_end = path.segments.len() - path_res.depth;
|
let base_ty_end = path.segments.len() - path_res.depth;
|
||||||
let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span,
|
let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span,
|
||||||
PathParamMode::Optional,
|
PathParamMode::Optional,
|
||||||
def,
|
path_res.base_def,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
node_id,
|
node_id,
|
||||||
&ty_segments[..base_ty_end],
|
&ty_segments[..base_ty_end],
|
||||||
&ty_segments[base_ty_end..]);
|
&ty_segments[base_ty_end..]);
|
||||||
|
|
||||||
|
// Resolve an associated constant or method on the previously resolved type.
|
||||||
let item_segment = path.segments.last().unwrap();
|
let item_segment = path.segments.last().unwrap();
|
||||||
let item_name = item_segment.name;
|
let item_name = item_segment.name;
|
||||||
let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
|
let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
|
||||||
Ok(def) => Some(def),
|
Ok(def) => def,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
let def = match error {
|
let def = match error {
|
||||||
method::MethodError::PrivateMatch(def) => Some(def),
|
method::MethodError::PrivateMatch(def) => def,
|
||||||
_ => None,
|
_ => Def::Err,
|
||||||
};
|
};
|
||||||
if item_name != keywords::Invalid.name() {
|
if item_name != keywords::Invalid.name() {
|
||||||
self.report_method_error(span, ty, item_name, None, error);
|
self.report_method_error(span, ty, item_name, None, error);
|
||||||
|
@ -3743,14 +3739,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(def) = def {
|
// Write back the new resolution.
|
||||||
// Write back the new resolution.
|
self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def));
|
||||||
self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution::new(def));
|
(def, Some(ty), slice::ref_slice(item_segment))
|
||||||
Some((Some(ty), slice::ref_slice(item_segment), def))
|
|
||||||
} else {
|
|
||||||
self.write_error(node_id);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1040,15 +1040,17 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
def: &hir::VariantData)
|
def: &hir::VariantData)
|
||||||
-> ty::AdtDefMaster<'tcx>
|
-> ty::AdtDefMaster<'tcx>
|
||||||
{
|
{
|
||||||
|
|
||||||
let did = ccx.tcx.map.local_def_id(it.id);
|
let did = ccx.tcx.map.local_def_id(it.id);
|
||||||
let ctor_id = if !def.is_struct() {
|
// Use separate constructor id for unit/tuple structs and reuse did for braced structs.
|
||||||
ccx.tcx.map.local_def_id(def.id())
|
let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None };
|
||||||
} else {
|
let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name,
|
||||||
did
|
ConstInt::Infer(0), def)];
|
||||||
};
|
let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants);
|
||||||
ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct,
|
if let Some(ctor_id) = ctor_id {
|
||||||
vec![convert_struct_variant(ccx, ctor_id, it.name, ConstInt::Infer(0), def)])
|
// Make adt definition available through constructor id as well.
|
||||||
|
ccx.tcx.insert_adt_def(ctor_id, adt);
|
||||||
|
}
|
||||||
|
adt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
|
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
|
||||||
|
|
|
@ -3225,42 +3225,6 @@ impl Foo for Bar {
|
||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0327: r##"
|
|
||||||
You cannot use associated items other than constant items as patterns. This
|
|
||||||
includes method items. Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail
|
|
||||||
enum B {}
|
|
||||||
|
|
||||||
impl B {
|
|
||||||
fn bb() -> i32 { 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
match 0 {
|
|
||||||
B::bb => {} // error: associated items in match patterns must
|
|
||||||
// be constants
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Please check that you're not using a method as a pattern. Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
enum B {
|
|
||||||
ba,
|
|
||||||
bb
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
match B::ba {
|
|
||||||
B::bb => {} // ok!
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0329: r##"
|
E0329: r##"
|
||||||
An attempt was made to access an associated constant through either a generic
|
An attempt was made to access an associated constant through either a generic
|
||||||
type parameter or `Self`. This is not supported yet. An example causing this
|
type parameter or `Self`. This is not supported yet. An example causing this
|
||||||
|
@ -4162,4 +4126,5 @@ register_diagnostics! {
|
||||||
E0527, // expected {} elements, found {}
|
E0527, // expected {} elements, found {}
|
||||||
E0528, // expected at least {} elements, found {}
|
E0528, // expected at least {} elements, found {}
|
||||||
E0529, // slice pattern expects array or slice, not `{}`
|
E0529, // slice pattern expects array or slice, not `{}`
|
||||||
|
E0533, // `{}` does not name a unit variant, unit struct or a constant
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(fn_traits)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
// revisions: ok oneuse transmute krisskross
|
// revisions: ok oneuse transmute krisskross
|
||||||
|
|
||||||
|
#![feature(fn_traits)]
|
||||||
#![allow(dead_code, unused_variables)]
|
#![allow(dead_code, unused_variables)]
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
|
@ -31,12 +31,14 @@ fn main() {
|
||||||
Empty1 => () // Not an error, `Empty1` is interpreted as a new binding
|
Empty1 => () // Not an error, `Empty1` is interpreted as a new binding
|
||||||
}
|
}
|
||||||
match e3 {
|
match e3 {
|
||||||
E::Empty3 => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
|
E::Empty3 => ()
|
||||||
|
//~^ ERROR `E::Empty3` does not name a unit variant, unit struct or a constant
|
||||||
}
|
}
|
||||||
match xe1 {
|
match xe1 {
|
||||||
XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
|
XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
|
||||||
}
|
}
|
||||||
match xe3 {
|
match xe3 {
|
||||||
XE::XEmpty3 => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
|
XE::XEmpty3 => ()
|
||||||
|
//~^ ERROR `XE::XEmpty3` does not name a unit variant, unit struct or a constant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct S;
|
||||||
fn main() {
|
fn main() {
|
||||||
match Foo::Baz {
|
match Foo::Baz {
|
||||||
Foo::Bar => {}
|
Foo::Bar => {}
|
||||||
//~^ ERROR `Foo::Bar` does not name a tuple variant or a tuple struct
|
//~^ ERROR `Foo::Bar` does not name a unit variant, unit struct or a constant
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,13 @@ impl MyTrait for Foo {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match 0u32 {
|
match 0u32 {
|
||||||
Foo::bar => {} //~ ERROR E0327
|
Foo::bar => {} //~ ERROR `Foo::bar` does not name a unit variant, unit struct or a constant
|
||||||
}
|
}
|
||||||
match 0u32 {
|
match 0u32 {
|
||||||
<Foo>::bar => {} //~ ERROR E0327
|
<Foo>::bar => {} //~ ERROR `bar` does not name a unit variant, unit struct or a constant
|
||||||
}
|
}
|
||||||
match 0u32 {
|
match 0u32 {
|
||||||
<Foo>::trait_bar => {} //~ ERROR E0327
|
<Foo>::trait_bar => {}
|
||||||
|
//~^ ERROR `trait_bar` does not name a unit variant, unit struct or a constant
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ impl S {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match 10 {
|
match 10 {
|
||||||
<S as Tr>::A::f::<u8> => {} //~ ERROR associated items in match patterns must be constants
|
<S as Tr>::A::f::<u8> => {}
|
||||||
|
//~^ ERROR `Tr::A::f<u8>` does not name a unit variant, unit struct or a constant
|
||||||
0 ... <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
|
0 ... <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(fn_traits)]
|
||||||
|
|
||||||
struct A<F: FnOnce()->T,T>(F::Output);
|
struct A<F: FnOnce()->T,T>(F::Output);
|
||||||
struct B<F: FnOnce()->T,T>(A<F,T>);
|
struct B<F: FnOnce()->T,T>(A<F,T>);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue