Overhaul typechecking of patterns
Instead of checking patterns in a top-down fashion with a known expected type on entry, this changes makes typeck establish appropriate constraints between a pattern and the expression it destructures, and lets inference compute the final types or produce good error messages if it's impossible.
This commit is contained in:
parent
3e9ce5afb7
commit
4380e96c04
@ -44,11 +44,9 @@ register_diagnostics!(
|
||||
E0025,
|
||||
E0026,
|
||||
E0027,
|
||||
E0028,
|
||||
E0029,
|
||||
E0030,
|
||||
E0031,
|
||||
E0032,
|
||||
E0033,
|
||||
E0034,
|
||||
E0035,
|
||||
|
@ -673,9 +673,14 @@ pub fn get_enum_variants(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
|
||||
let ctor_ty = item_type(ast::DefId { krate: cdata.cnum, node: id},
|
||||
item, tcx, cdata);
|
||||
let name = item_name(&*intr, item);
|
||||
let arg_tys = match ty::get(ctor_ty).sty {
|
||||
ty::ty_bare_fn(ref f) => f.sig.inputs.clone(),
|
||||
_ => Vec::new(), // Nullary enum variant.
|
||||
let (ctor_ty, arg_tys) = match ty::get(ctor_ty).sty {
|
||||
ty::ty_bare_fn(ref f) =>
|
||||
(Some(ctor_ty), f.sig.inputs.clone()),
|
||||
_ => // Nullary or struct enum variant.
|
||||
(None, get_struct_fields(intr.clone(), cdata, did.node)
|
||||
.iter()
|
||||
.map(|field_ty| get_type(cdata, field_ty.id.node, tcx).ty)
|
||||
.collect())
|
||||
};
|
||||
match variant_disr_val(item) {
|
||||
Some(val) => { disr_val = val; }
|
||||
|
@ -667,21 +667,12 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
||||
|
||||
let struct_type = ty::lookup_item_type(self.tcx, id).ty;
|
||||
let struct_desc = match ty::get(struct_type).sty {
|
||||
ty::ty_struct(_, _) => format!("struct `{}`", ty::item_path_str(self.tcx, id)),
|
||||
ty::ty_bare_fn(ty::BareFnTy { sig: ty::FnSig { output, .. }, .. }) => {
|
||||
// Struct `id` is really a struct variant of an enum,
|
||||
// and we're really looking at the variant's constructor
|
||||
// function. So get the return type for a detailed error
|
||||
// message.
|
||||
let enum_id = match ty::get(output).sty {
|
||||
ty::ty_enum(id, _) => id,
|
||||
_ => self.tcx.sess.span_bug(span, "enum variant doesn't \
|
||||
belong to an enum")
|
||||
};
|
||||
ty::ty_struct(_, _) =>
|
||||
format!("struct `{}`", ty::item_path_str(self.tcx, id)),
|
||||
ty::ty_enum(enum_id, _) =>
|
||||
format!("variant `{}` of enum `{}`",
|
||||
ty::with_path(self.tcx, id, |mut p| p.last().unwrap()),
|
||||
ty::item_path_str(self.tcx, enum_id))
|
||||
}
|
||||
ty::item_path_str(self.tcx, enum_id)),
|
||||
_ => self.tcx.sess.span_bug(span, "can't find struct for field")
|
||||
};
|
||||
let msg = match name {
|
||||
|
@ -50,7 +50,7 @@ use syntax::ast::{CrateNum, DefId, FnStyle, Ident, ItemTrait, LOCAL_CRATE};
|
||||
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
|
||||
use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField};
|
||||
use syntax::ast::{Visibility};
|
||||
use syntax::ast_util::{mod, PostExpansionMethod, is_local, lit_is_str};
|
||||
use syntax::ast_util::{mod, is_local, lit_is_str, local_def, PostExpansionMethod};
|
||||
use syntax::attr::{mod, AttrMetaMethods};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::{mod, InternedString};
|
||||
@ -4221,7 +4221,7 @@ pub fn ty_to_def_id(ty: t) -> Option<ast::DefId> {
|
||||
pub struct VariantInfo {
|
||||
pub args: Vec<t>,
|
||||
pub arg_names: Option<Vec<ast::Ident> >,
|
||||
pub ctor_ty: t,
|
||||
pub ctor_ty: Option<t>,
|
||||
pub name: ast::Name,
|
||||
pub id: ast::DefId,
|
||||
pub disr_val: Disr,
|
||||
@ -4249,7 +4249,7 @@ impl VariantInfo {
|
||||
return VariantInfo {
|
||||
args: arg_tys,
|
||||
arg_names: None,
|
||||
ctor_ty: ctor_ty,
|
||||
ctor_ty: Some(ctor_ty),
|
||||
name: ast_variant.node.name.name,
|
||||
id: ast_util::local_def(ast_variant.node.id),
|
||||
disr_val: discriminant,
|
||||
@ -4262,7 +4262,8 @@ impl VariantInfo {
|
||||
|
||||
assert!(fields.len() > 0);
|
||||
|
||||
let arg_tys = ty_fn_args(ctor_ty).iter().map(|a| *a).collect();
|
||||
let arg_tys = struct_def.fields.iter()
|
||||
.map(|field| node_id_to_type(cx, field.node.id)).collect();
|
||||
let arg_names = fields.iter().map(|field| {
|
||||
match field.node.kind {
|
||||
NamedField(ident, _) => ident,
|
||||
@ -4274,7 +4275,7 @@ impl VariantInfo {
|
||||
return VariantInfo {
|
||||
args: arg_tys,
|
||||
arg_names: Some(arg_names),
|
||||
ctor_ty: ctor_ty,
|
||||
ctor_ty: None,
|
||||
name: ast_variant.node.name.name,
|
||||
id: ast_util::local_def(ast_variant.node.id),
|
||||
disr_val: discriminant,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -117,7 +117,7 @@ use util::ppaux;
|
||||
use util::ppaux::{UserString, Repr};
|
||||
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::{Cell, Ref, RefCell};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hashmap::{Occupied, Vacant};
|
||||
use std::mem::replace;
|
||||
@ -1815,6 +1815,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn item_substs<'a>(&'a self) -> Ref<'a, NodeMap<ty::ItemSubsts>> {
|
||||
self.inh.item_substs.borrow()
|
||||
}
|
||||
|
||||
pub fn opt_node_ty_substs(&self,
|
||||
id: ast::NodeId,
|
||||
f: |&ty::ItemSubsts|) {
|
||||
|
@ -236,10 +236,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
|
||||
};
|
||||
|
||||
convert_struct(ccx, &**struct_def, pty, variant.node.id);
|
||||
|
||||
let input_tys: Vec<_> = struct_def.fields.iter().map(
|
||||
|f| ty::node_id_to_type(ccx.tcx, f.node.id)).collect();
|
||||
ty::mk_ctor_fn(tcx, scope, input_tys.as_slice(), enum_ty)
|
||||
enum_ty
|
||||
}
|
||||
};
|
||||
|
||||
|
30
src/test/run-pass/issue-8783.rs
Normal file
30
src/test/run-pass/issue-8783.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::default::Default;
|
||||
|
||||
struct X { pub x: uint }
|
||||
impl Default for X {
|
||||
fn default() -> X {
|
||||
X { x: 42u }
|
||||
}
|
||||
}
|
||||
|
||||
struct Y<T> { pub y: T }
|
||||
impl<T: Default> Default for Y<T> {
|
||||
fn default() -> Y<T> {
|
||||
Y { y: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let X { x: _ } = Default::default();
|
||||
let Y { y: X { x } } = Default::default();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user