use hir::def::Def;
use rustc::infer::{self, InferOk, TypeOrigin};
use hir::pat_util::EnumerateAndAdjustIterator;
-use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
use check::{FnCtxt, Expectation};
use lint;
debug!("check_pat(pat={:?},expected={:?})", pat, expected);
- match pat.node {
+ let ty = match pat.node {
PatKind::Wild => {
- self.write_ty(pat.id, expected);
+ expected
}
PatKind::Lit(ref lt) => {
- self.check_expr(<);
- let expr_ty = self.expr_ty(<);
+ let ty = self.check_expr(<);
// Byte string patterns behave the same way as array patterns
// They can denote both statically and dynamically sized byte arrays
- let mut pat_ty = expr_ty;
+ let mut pat_ty = ty;
if let hir::ExprLit(ref lt) = lt.node {
if let ast::LitKind::ByteStr(_) = lt.node {
let expected_ty = self.structurally_resolved_type(pat.span, expected);
}
}
- self.write_ty(pat.id, pat_ty);
-
// somewhat surprising: in this case, the subtyping
// relation goes the opposite way as the other
// cases. Actually what we really want is not a subtyping
// relation at all but rather that there exists a LUB (so
// that they can be compared). However, in practice,
// constants are always scalars or strings. For scalars
- // subtyping is irrelevant, and for strings `expr_ty` is
+ // subtyping is irrelevant, and for strings `ty` is
// type is `&'static str`, so if we say that
//
// &'static str <: expected
//
// that's equivalent to there existing a LUB.
self.demand_suptype(pat.span, expected, pat_ty);
+ pat_ty
}
PatKind::Range(ref begin, ref end) => {
- self.check_expr(begin);
- self.check_expr(end);
-
- let lhs_ty = self.expr_ty(begin);
- let rhs_ty = self.expr_ty(end);
+ let lhs_ty = self.check_expr(begin);
+ let rhs_ty = self.check_expr(end);
// Check that both end-points are of numeric or char type.
let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
// it to type the entire expression.
let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
- self.write_ty(pat.id, common_type);
-
// 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, rhs_ty);
+ common_type
}
PatKind::Binding(bm, _, ref sub) => {
let typ = self.local_ty(pat.span, pat.id);
// and T is the expected type.
let region_var = self.next_region_var(infer::PatternRegion(pat.span));
let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl };
- let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt);
+ let region_ty = tcx.mk_ref(region_var, mt);
// `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
// required. However, we use equality, which is stronger. See (*) for
}
}
- self.write_ty(pat.id, typ);
-
// if there are multiple arms, make sure they all agree on
// what the type of the binding `x` ought to be
match tcx.expect_def(pat.id) {
Def::Err => {}
- Def::Local(_, var_id) => {
+ Def::Local(def_id) => {
+ let var_id = tcx.map.as_local_node_id(def_id).unwrap();
if var_id != pat.id {
let vt = self.local_ty(pat.span, var_id);
self.demand_eqtype(pat.span, vt, typ);
if let Some(ref p) = *sub {
self.check_pat(&p, expected);
}
+
+ typ
}
PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
- self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
+ self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected)
}
PatKind::Path(ref opt_qself, ref path) => {
let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
- self.check_pat_path(pat, opt_qself_ty, path, expected);
+ self.check_pat_path(pat, opt_qself_ty, path, expected)
}
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)
}
PatKind::Tuple(ref elements, ddpos) => {
let mut expected_len = elements.len();
let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect();
let pat_ty = tcx.mk_tup(element_tys.clone());
- self.write_ty(pat.id, pat_ty);
self.demand_eqtype(pat.span, expected, pat_ty);
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
self.check_pat(elem, &element_tys[i]);
}
+ pat_ty
}
PatKind::Box(ref inner) => {
let inner_ty = self.next_ty_var();
// think any errors can be introduced by using
// `demand::eqtype`.
self.demand_eqtype(pat.span, expected, uniq_ty);
- self.write_ty(pat.id, uniq_ty);
self.check_pat(&inner, inner_ty);
+ uniq_ty
} else {
- self.write_error(pat.id);
self.check_pat(&inner, tcx.types.err);
+ tcx.types.err
}
}
PatKind::Ref(ref inner, mutbl) => {
let inner_ty = self.next_ty_var();
let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
let region = self.next_region_var(infer::PatternRegion(pat.span));
- let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
+ let rptr_ty = tcx.mk_ref(region, mt);
self.demand_eqtype(pat.span, expected, rptr_ty);
(rptr_ty, inner_ty)
}
};
- self.write_ty(pat.id, rptr_ty);
self.check_pat(&inner, inner_ty);
+ rptr_ty
} else {
- self.write_error(pat.id);
self.check_pat(&inner, tcx.types.err);
+ tcx.types.err
}
}
PatKind::Vec(ref before, ref slice, ref after) => {
let min_len = before.len() + after.len();
if slice.is_none() {
if min_len != size {
- span_err!(tcx.sess, pat.span, E0527,
- "pattern requires {} elements but array has {}",
- min_len, size);
+ struct_span_err!(
+ tcx.sess, pat.span, E0527,
+ "pattern requires {} elements but array has {}",
+ min_len, size)
+ .span_label(pat.span, &format!("expected {} elements",size))
+ .emit();
}
(inner_ty, tcx.types.err)
} else if let Some(rest) = size.checked_sub(min_len) {
(inner_ty, tcx.mk_array(inner_ty, rest))
} else {
- span_err!(tcx.sess, pat.span, E0528,
- "pattern requires at least {} elements but array has {}",
- min_len, size);
+ struct_span_err!(tcx.sess, pat.span, E0528,
+ "pattern requires at least {} elements but array has {}",
+ min_len, size)
+ .span_label(pat.span,
+ &format!("pattern cannot match array of {} elements", size))
+ .emit();
(inner_ty, tcx.types.err)
}
}
_ => {}
}
}
- err.emit();
+
+ err.span_label( pat.span,
+ &format!("pattern cannot match with input type `{}`", expected_ty)
+ ).emit();
}
(tcx.types.err, tcx.types.err)
}
};
- self.write_ty(pat.id, expected_ty);
-
for elt in before {
self.check_pat(&elt, inner_ty);
}
for elt in after {
self.check_pat(&elt, inner_ty);
}
+ expected_ty
}
- }
+ };
+
+ self.write_ty(pat.id, ty);
// (*) In most of the cases above (literals and constants being
// the exception), we relate types using strict equality, evewn
if let ty::TyTrait(..) = mt.ty.sty {
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
- span_err!(self.tcx.sess, span, E0033,
- "type `{}` cannot be dereferenced",
- self.ty_to_string(expected));
+ let type_str = self.ty_to_string(expected);
+ struct_span_err!(self.tcx.sess, span, E0033,
+ "type `{}` cannot be dereferenced", type_str)
+ .span_label(span, &format!("type `{}` cannot be dereferenced", type_str))
+ .emit();
return false
}
}
discrim: &'gcx hir::Expr,
arms: &'gcx [hir::Arm],
expected: Expectation<'tcx>,
- match_src: hir::MatchSource) {
+ match_src: hir::MatchSource) -> Ty<'tcx> {
let tcx = self.tcx;
// Not entirely obvious: if matches may create ref bindings, we
});
let discrim_ty;
if let Some(m) = contains_ref_bindings {
- self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
- discrim_ty = self.expr_ty(discrim);
+ discrim_ty = self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
} else {
// ...but otherwise we want to use any supertype of the
// discriminant. This is sort of a workaround, see note (*) in
}
_ => result_ty
};
+
for (i, arm) in arms.iter().enumerate() {
if let Some(ref e) = arm.guard {
self.check_expr_has_type(e, tcx.types.bool);
}
- self.check_expr_with_expectation(&arm.body, expected);
- let arm_ty = self.expr_ty(&arm.body);
+ let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
if result_ty.references_error() || arm_ty.references_error() {
result_ty = tcx.types.err;
})
} else if i == 0 {
// Special-case the first arm, as it has no "previous expressions".
- self.try_coerce(&arm.body, coerce_first)
+ self.try_coerce(&arm.body, arm_ty, coerce_first)
} else {
let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
- self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body)
+ self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
};
result_ty = match result {
};
}
- self.write_ty(expr.id, result_ty);
+ result_ty
}
}
path: &hir::Path,
fields: &'gcx [Spanned<hir::FieldPat>],
etc: bool,
- expected: Ty<'tcx>)
+ expected: Ty<'tcx>) -> Ty<'tcx>
{
// Resolve the path and check the definition for errors.
let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id,
pat.span) {
variant_ty
} else {
- self.write_error(pat.id);
for field in fields {
self.check_pat(&field.node.pat, self.tcx.types.err);
}
- return;
+ return self.tcx.types.err;
};
// Type check the path.
self.demand_eqtype(pat.span, expected, pat_ty);
// Type check subpatterns.
- let substs = match pat_ty.sty {
- ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
- _ => span_bug!(pat.span, "struct variant is not an ADT")
- };
- self.check_struct_pat_fields(pat.span, fields, variant, substs, etc);
+ self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc);
+ pat_ty
}
fn check_pat_path(&self,
pat: &hir::Pat,
opt_self_ty: Option<Ty<'tcx>>,
path: &hir::Path,
- expected: Ty<'tcx>)
+ expected: Ty<'tcx>) -> Ty<'tcx>
{
let tcx = self.tcx;
let report_unexpected_def = || {
span_err!(tcx.sess, pat.span, E0533,
"`{}` does not name a unit variant, unit struct or a constant",
pprust::path_to_string(path));
- self.write_error(pat.id);
};
// Resolve the path and check the definition for errors.
match def {
Def::Err => {
self.set_tainted_by_errors();
- self.write_error(pat.id);
- return;
+ return tcx.types.err;
}
Def::Method(..) => {
report_unexpected_def();
- return;
+ return tcx.types.err;
}
Def::Variant(..) => {
let variant = tcx.expect_variant_def(def);
if variant.kind != VariantKind::Unit {
report_unexpected_def();
- return;
+ return tcx.types.err;
}
}
Def::Struct(ctor_did) => {
let variant = tcx.lookup_adt_def(did).struct_variant();
if variant.kind != VariantKind::Unit {
report_unexpected_def();
- return;
+ return tcx.types.err;
}
}
Def::Const(..) | Def::AssociatedConst(..) => {} // OK
}
// Type check the path.
- let scheme = tcx.lookup_item_type(def.def_id());
- let predicates = tcx.lookup_predicates(def.def_id());
- let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
- opt_ty, def, pat.span, pat.id);
+ let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
self.demand_suptype(pat.span, expected, pat_ty);
+ pat_ty
}
fn check_pat_tuple_struct(&self,
path: &hir::Path,
subpats: &'gcx [P<hir::Pat>],
ddpos: Option<usize>,
- expected: Ty<'tcx>)
+ expected: Ty<'tcx>) -> Ty<'tcx>
{
let tcx = self.tcx;
let on_error = || {
- self.write_error(pat.id);
for pat in subpats {
self.check_pat(&pat, tcx.types.err);
}
tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
pat.id, pat.span, msg);
} else {
- span_err!(tcx.sess, pat.span, E0164, "{}", msg);
+ struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
+ .span_label(pat.span, &format!("not a tuple variant or struct")).emit();
on_error();
}
};
Def::Err => {
self.set_tainted_by_errors();
on_error();
- return;
+ return tcx.types.err;
}
Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
report_unexpected_def(false);
- return;
+ return tcx.types.err;
}
Def::Variant(..) => {
tcx.expect_variant_def(def)
report_unexpected_def(true);
} else if variant.kind != VariantKind::Tuple {
report_unexpected_def(false);
- return;
+ return tcx.types.err;
}
// Type check the path.
- let scheme = tcx.lookup_item_type(def.def_id());
- let scheme = if scheme.ty.is_fn() {
+ let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
+ let pat_ty = if pat_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();
- ty::TypeScheme { ty: fn_ret, generics: scheme.generics }
+ tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap()
} else {
// Leave the type as is for unit structs (backward compatibility).
- scheme
+ pat_ty
};
- let predicates = tcx.lookup_predicates(def.def_id());
- let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
- opt_ty, def, pat.span, pat.id);
self.demand_eqtype(pat.span, expected, pat_ty);
// Type check subpatterns.
if subpats.len() == variant.fields.len() ||
subpats.len() < variant.fields.len() && ddpos.is_some() {
let substs = match pat_ty.sty {
- ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
+ ty::TyAdt(_, substs) => substs,
ref ty => bug!("unexpected pattern type {:?}", ty),
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
variant.fields.len(), fields_ending, subpats.len()))
.emit();
on_error();
+ return tcx.types.err;
}
+ pat_ty
}
- /// `path` is the AST path item naming the type of this struct.
- /// `fields` is the field patterns of the struct pattern.
- /// `struct_fields` describes the type of each field of the struct.
- /// `struct_id` is the ID of the struct.
- /// `etc` is true if the pattern said '...' and false otherwise.
- pub fn check_struct_pat_fields(&self,
- span: Span,
- fields: &'gcx [Spanned<hir::FieldPat>],
- variant: ty::VariantDef<'tcx>,
- substs: &Substs<'tcx>,
- etc: bool) {
+ fn check_struct_pat_fields(&self,
+ adt_ty: Ty<'tcx>,
+ span: Span,
+ variant: ty::VariantDef<'tcx>,
+ fields: &'gcx [Spanned<hir::FieldPat>],
+ etc: bool) {
let tcx = self.tcx;
+ let (substs, kind_name) = match adt_ty.sty {
+ ty::TyAdt(adt, substs) => (substs, adt.variant_descr()),
+ _ => span_bug!(span, "struct pattern is not an ADT")
+ };
+
// Index the struct fields' types.
let field_map = variant.fields
.iter()
.map(|f| self.field_ty(span, f, substs))
.unwrap_or_else(|| {
struct_span_err!(tcx.sess, span, E0026,
- "struct `{}` does not have a field named `{}`",
+ "{} `{}` does not have a field named `{}`",
+ kind_name,
tcx.item_path_str(variant.did),
field.name)
.span_label(span,
- &format!("struct `{}` does not have field `{}`",
+ &format!("{} `{}` does not have field `{}`",
+ kind_name,
tcx.item_path_str(variant.did),
field.name))
.emit();
self.check_pat(&field.pat, field_ty);
}
- // Report an error if not all the fields were specified.
- if !etc {
+ // Report an error if incorrect number of the fields were specified.
+ if kind_name == "union" {
+ if fields.len() != 1 {
+ tcx.sess.span_err(span, "union patterns should have exactly one field");
+ }
+ if etc {
+ tcx.sess.span_err(span, "`..` cannot be used in union patterns");
+ }
+ } else if !etc {
for field in variant.fields
.iter()
.filter(|field| !used_fields.contains_key(&field.name)) {