Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typecheck refactor for ! #35787

Merged
merged 20 commits into from
Sep 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 44 additions & 52 deletions src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

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(&lt);
let expr_ty = self.expr_ty(&lt);
let ty = self.check_expr(&lt);

// 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);
Expand All @@ -55,28 +54,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}

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();
Expand Down Expand Up @@ -105,11 +100,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// 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);
Expand All @@ -136,8 +130,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}

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) {
Expand All @@ -154,16 +146,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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();
Expand All @@ -178,11 +172,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

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();
Expand All @@ -193,11 +187,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// 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) => {
Expand Down Expand Up @@ -225,11 +219,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
};

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) => {
Expand Down Expand Up @@ -281,8 +275,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
};

self.write_ty(pat.id, expected_ty);

for elt in before {
self.check_pat(&elt, inner_ty);
}
Expand All @@ -292,8 +284,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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
Expand Down Expand Up @@ -371,7 +366,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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
Expand All @@ -385,8 +380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
});
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
Expand Down Expand Up @@ -425,12 +419,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
_ => 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;
Expand Down Expand Up @@ -460,10 +454,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
})
} 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 {
Expand All @@ -480,7 +474,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
};
}

self.write_ty(expr.id, result_ty);
result_ty
}
}

Expand All @@ -490,39 +484,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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.
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.
Expand All @@ -531,18 +524,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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(..) | Def::Struct(..) => {
let variant = tcx.expect_variant_def(def);
if variant.kind != VariantKind::Unit {
report_unexpected_def();
return;
return tcx.types.err;
}
}
Def::Const(..) | Def::AssociatedConst(..) => {} // OK
Expand All @@ -552,18 +544,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Type check the path.
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,
pat: &hir::Pat,
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);
}
Expand All @@ -587,11 +579,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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(..) | Def::Struct(..) => {
tcx.expect_variant_def(def)
Expand All @@ -604,20 +596,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
report_unexpected_def(true);
} else if variant.kind != VariantKind::Tuple {
report_unexpected_def(false);
return;
return tcx.types.err;
}

// Type check the path.
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.
tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap()
} else {
// Leave the type as is for unit structs (backward compatibility).
pat_ty
};
self.write_ty(pat.id, pat_ty);
self.demand_eqtype(pat.span, expected, pat_ty);

// Type check subpatterns.
Expand Down Expand Up @@ -650,7 +640,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
variant.fields.len(), fields_ending, subpats.len()))
.emit();
on_error();
return tcx.types.err;
}
pat_ty
}

fn check_struct_pat_fields(&self,
Expand Down
Loading