use middle::infer::type_variable;
use middle::pat_util::{self, pat_id_map};
use middle::privacy::{AllPublic, LastMod};
-use middle::region::{self, CodeExtent};
+use middle::region::{self};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
use middle::traits::{self, report_fulfillment_errors};
use middle::ty::{FnSig, GenericPredicates, TypeScheme};
pub mod demand;
pub mod method;
mod upvar;
-pub mod wf;
+mod wf;
+mod wfcheck;
mod cast;
mod closure;
mod callee;
}
}
-pub fn check_item_types(ccx: &CrateCtxt) {
+pub fn check_wf_old(ccx: &CrateCtxt) {
+ // FIXME(#25759). The new code below is much more reliable but (for now)
+ // only generates warnings. So as to ensure that we continue
+ // getting errors where we used to get errors, we run the old wf
+ // code first and abort if it encounters any errors. If no abort
+ // comes, we run the new code and issue warnings.
let krate = ccx.tcx.map.krate();
let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
visit::walk_crate(&mut visit, krate);
// If types are not well-formed, it leads to all manner of errors
// downstream, so stop reporting errors at this point.
ccx.tcx.sess.abort_if_errors();
+}
- let mut visit = CheckItemTypesVisitor { ccx: ccx };
+pub fn check_wf_new(ccx: &CrateCtxt) {
+ let krate = ccx.tcx.map.krate();
+ let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
visit::walk_crate(&mut visit, krate);
+ // If types are not well-formed, it leads to all manner of errors
+ // downstream, so stop reporting errors at this point.
+ ccx.tcx.sess.abort_if_errors();
+}
+
+pub fn check_item_types(ccx: &CrateCtxt) {
+ let krate = ccx.tcx.map.krate();
+ let mut visit = CheckItemTypesVisitor { ccx: ccx };
+ visit::walk_crate(&mut visit, krate);
ccx.tcx.sess.abort_if_errors();
+}
+pub fn check_item_bodies(ccx: &CrateCtxt) {
+ let krate = ccx.tcx.map.krate();
let mut visit = CheckItemBodiesVisitor { ccx: ccx };
visit::walk_crate(&mut visit, krate);
ccx.tcx.sess.abort_if_errors();
+}
+pub fn check_drop_impls(ccx: &CrateCtxt) {
for drop_method_did in ccx.tcx.destructors.borrow().iter() {
if drop_method_did.krate == ast::LOCAL_CRATE {
let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node);
fcx.select_all_obligations_and_apply_defaults();
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
- fcx.select_all_obligations_or_error();
+ fcx.select_obligations_where_possible();
fcx.check_casts();
-
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
if let ty::FnConverging(ret_ty) = ret_ty {
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
- fn_sig_tys.push(ret_ty);
+ fn_sig_tys.push(ret_ty); // FIXME(#25759) just take implied bounds from the arguments
}
debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}",
// Add formal parameters.
for (arg_ty, input) in arg_tys.iter().zip(&decl.inputs) {
+ // The type of the argument must be well-formed.
+ //
+ // NB -- this is now checked in wfcheck, but that
+ // currently only results in warnings, so we issue an
+ // old-style WF obligation here so that we still get the
+ // errors that we used to get.
+ fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
+
// Create type variables for each argument.
pat_util::pat_bindings(
&tcx.def_map,
cause)
}
- /// Returns the type of `def_id` with all generics replaced by by fresh type/region variables.
- /// Also returns the substitution from the type parameters on `def_id` to the fresh variables.
- /// Registers any trait obligations specified on `def_id` at the same time.
+ /// Instantiates the type in `did` with the generics in `path` and returns
+ /// it (registering the necessary trait obligations along the way).
///
- /// Note that function is only intended to be used with types (notably, not fns). This is
- /// because it doesn't do any instantiation of late-bound regions.
+ /// Note that this function is only intended to be used with type-paths,
+ /// not with value-paths.
pub fn instantiate_type(&self,
- span: Span,
- def_id: ast::DefId)
- -> TypeAndSubsts<'tcx>
+ did: ast::DefId,
+ path: &ast::Path)
+ -> Ty<'tcx>
{
+ debug!("instantiate_type(did={:?}, path={:?})", did, path);
let type_scheme =
- self.tcx().lookup_item_type(def_id);
+ self.tcx().lookup_item_type(did);
let type_predicates =
- self.tcx().lookup_predicates(def_id);
- let substs =
- self.infcx().fresh_substs_for_generics(
- span,
- &type_scheme.generics);
+ self.tcx().lookup_predicates(did);
+ let substs = astconv::ast_path_substs_for_ty(self, self,
+ path.span,
+ PathParamMode::Optional,
+ &type_scheme.generics,
+ path.segments.last().unwrap());
+ debug!("instantiate_type: ty={:?} substs={:?}", &type_scheme.ty, &substs);
let bounds =
- self.instantiate_bounds(span, &substs, &type_predicates);
+ self.instantiate_bounds(path.span, &substs, &type_predicates);
self.add_obligations_for_parameters(
traits::ObligationCause::new(
- span,
+ path.span,
self.body_id,
- traits::ItemObligation(def_id)),
+ traits::ItemObligation(did)),
&bounds);
- let monotype =
- self.instantiate_type_scheme(span, &substs, &type_scheme.ty);
- TypeAndSubsts {
- ty: monotype,
- substs: substs
- }
+ self.instantiate_type_scheme(path.span, &substs, &type_scheme.ty)
}
- /// Returns the type that this AST path refers to. If the path has no type
- /// parameters and the corresponding type has type parameters, fresh type
- /// and/or region variables are substituted.
- ///
- /// This is used when checking the constructor in struct literals.
- fn instantiate_struct_literal_ty(&self,
- did: ast::DefId,
- path: &ast::Path)
- -> TypeAndSubsts<'tcx>
+ /// Return the dict-like variant corresponding to a given `Def`.
+ pub fn def_struct_variant(&self,
+ def: def::Def)
+ -> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
{
- let tcx = self.tcx();
-
- let ty::TypeScheme { generics, ty: decl_ty } =
- tcx.lookup_item_type(did);
-
- let substs = astconv::ast_path_substs_for_ty(self, self,
- path.span,
- PathParamMode::Optional,
- &generics,
- path.segments.last().unwrap());
-
- let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
+ let (adt, variant) = match def {
+ def::DefVariant(enum_id, variant_id, true) => {
+ let adt = self.tcx().lookup_adt_def(enum_id);
+ (adt, adt.variant_with_id(variant_id))
+ }
+ def::DefTy(did, _) | def::DefStruct(did) => {
+ let typ = self.tcx().lookup_item_type(did);
+ if let ty::TyStruct(adt, _) = typ.ty.sty {
+ (adt, adt.struct_variant())
+ } else {
+ return None;
+ }
+ }
+ _ => return None
+ };
- TypeAndSubsts { substs: substs, ty: ty }
+ if let ty::VariantKind::Dict = variant.kind() {
+ Some((adt, variant))
+ } else {
+ None
+ }
}
+
pub fn write_nil(&self, node_id: ast::NodeId) {
self.write_ty(node_id, self.tcx().mk_nil());
}
pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> {
let t = ast_ty_to_ty(self, self, ast_t);
- let mut bounds_checker = wf::BoundsChecker::new(self,
- self.body_id,
- None);
- bounds_checker.check_ty(t, ast_t.span);
+ // Generally speaking, we must check that types entered by the
+ // user are well-formed. This is not true for `_`, since those
+ // types are generated by inference. Now, you might think that
+ // we could as well generate a WF obligation -- but
+ // unfortunately that breaks code like `foo as *const _`,
+ // because those type variables wind up being unconstrained
+ // until very late. Nasty. Probably it'd be best to refactor
+ // that code path, but that's tricky because of
+ // defaults. Argh!
+ match ast_t.node {
+ ast::TyInfer => { }
+ _ => { self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); }
+ }
t
}
fulfillment_cx.register_region_obligation(ty, region, cause);
}
- pub fn add_default_region_param_bounds(&self,
- substs: &Substs<'tcx>,
- expr: &ast::Expr)
+ /// Registers an obligation for checking later, during regionck, that the type `ty` must
+ /// outlive the region `r`.
+ pub fn register_wf_obligation(&self,
+ ty: Ty<'tcx>,
+ span: Span,
+ code: traits::ObligationCauseCode<'tcx>)
+ {
+ // WF obligations never themselves fail, so no real need to give a detailed cause:
+ let cause = traits::ObligationCause::new(span, self.body_id, code);
+ self.register_predicate(traits::Obligation::new(cause, ty::Predicate::WellFormed(ty)));
+ }
+
+ pub fn register_old_wf_obligation(&self,
+ ty: Ty<'tcx>,
+ span: Span,
+ code: traits::ObligationCauseCode<'tcx>)
+ {
+ // Registers an "old-style" WF obligation that uses the
+ // implicator code. This is basically a buggy version of
+ // `register_wf_obligation` that is being kept around
+ // temporarily just to help with phasing in the newer rules.
+ //
+ // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually
+ let cause = traits::ObligationCause::new(span, self.body_id, code);
+ self.register_region_obligation(ty, ty::ReEmpty, cause);
+ }
+
+ /// Registers obligations that all types appearing in `substs` are well-formed.
+ pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &ast::Expr)
{
for &ty in &substs.types {
- let default_bound = ty::ReScope(CodeExtent::from_node_id(expr.id));
- let cause = traits::ObligationCause::new(expr.span, self.body_id,
- traits::MiscObligation);
- self.register_region_obligation(ty, default_bound, cause);
+ self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
}
}
}
}
- // Only for fields! Returns <none> for methods>
- // Indifferent to privacy flags
- pub fn lookup_field_ty(&self,
- span: Span,
- struct_def: &'tcx ty::ADTDef<'tcx>,
- items: &[ty::FieldTy],
- fieldname: ast::Name,
- substs: &subst::Substs<'tcx>)
- -> Option<Ty<'tcx>>
- {
- let o_field = items.iter().find(|f| f.name == fieldname);
- o_field.map(|f| self.tcx().lookup_field_type(struct_def.did, f.id, substs))
- .map(|t| self.normalize_associated_types_in(span, &t))
- }
-
- pub fn lookup_tup_field_ty(&self,
- span: Span,
- struct_def: &'tcx ty::ADTDef<'tcx>,
- items: &[ty::FieldTy],
- idx: usize,
- substs: &subst::Substs<'tcx>)
- -> Option<Ty<'tcx>>
+ // FIXME(arielb1): use this instead of field.ty everywhere
+ pub fn field_ty(&self,
+ span: Span,
+ field: ty::FieldDef<'tcx>,
+ substs: &Substs<'tcx>)
+ -> Ty<'tcx>
{
- let o_field = if idx < items.len() { Some(&items[idx]) } else { None };
- o_field.map(|f| self.tcx().lookup_field_type(struct_def.did, f.id, substs))
- .map(|t| self.normalize_associated_types_in(span, &t))
+ self.normalize_associated_types_in(span,
+ &field.ty(self.tcx(), substs))
}
+ // Only for fields! Returns <none> for methods>
+ // Indifferent to privacy flags
fn check_casts(&self) {
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
for cast in deferred_cast_checks.drain(..) {
1
};
+ // All the input types from the fn signature must outlive the call
+ // so as to validate implied bounds.
+ for &fn_input_ty in fn_inputs {
+ fcx.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
+ }
+
let mut expected_arg_tys = expected_arg_tys;
let expected_arg_count = fn_inputs.len();
let formal_tys = if tuple_arguments == TupleArguments {
Expectation::rvalue_hint(fcx.tcx(), ty)
});
- check_expr_with_unifier(fcx, &**arg,
+ check_expr_with_unifier(fcx,
+ &**arg,
expected.unwrap_or(ExpectHasType(formal_ty)),
NoPreference, || {
// 2. Coerce to the most detailed type that could be coerced
match base_t.sty {
ty::TyStruct(base_def, substs) => {
debug!("struct named {:?}", base_t);
- let fields = tcx.lookup_struct_fields(base_def.did);
- fcx.lookup_field_ty(expr.span, base_def, &fields[..],
- field.node.name, &(*substs))
+ base_def.struct_variant()
+ .find_field_named(field.node.name)
+ .map(|f| fcx.field_ty(expr.span, f, substs))
}
_ => None
}
},
expr_t, None);
if let ty::TyStruct(def, _) = expr_t.sty {
- suggest_field_names(def.did, field, tcx, vec![]);
+ suggest_field_names(def.struct_variant(), field, tcx, vec![]);
}
}
}
// displays hints about the closest matches in field names
- fn suggest_field_names<'tcx>(variant_id: ast::DefId,
+ fn suggest_field_names<'tcx>(variant: ty::VariantDef<'tcx>,
field: &ast::SpannedIdent,
tcx: &ty::ctxt<'tcx>,
skip : Vec<InternedString>) {
let name = field.node.name.as_str();
// only find fits with at least one matching letter
let mut best_dist = name.len();
- let fields = tcx.lookup_struct_fields(variant_id);
let mut best = None;
- for elem in &fields {
+ for elem in &variant.fields {
let n = elem.name.as_str();
// ignore already set fields
if skip.iter().any(|x| *x == n) {
continue;
}
// ignore private fields from non-local crates
- if variant_id.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public {
+ if variant.did.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public {
continue;
}
let dist = lev_distance(&n, &name);
lvalue_pref: LvaluePreference,
base: &'tcx ast::Expr,
idx: codemap::Spanned<usize>) {
- let tcx = fcx.ccx.tcx;
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
let expr_t = structurally_resolved_type(fcx, expr.span,
fcx.expr_ty(base));
|base_t, _| {
match base_t.sty {
ty::TyStruct(base_def, substs) => {
- tuple_like = base_def.is_tuple_struct(tcx);
+ tuple_like = base_def.struct_variant().is_tuple_struct();
if tuple_like {
debug!("tuple struct named {:?}", base_t);
- let fields = tcx.lookup_struct_fields(base_def.did);
- fcx.lookup_tup_field_ty(expr.span, base_def, &fields[..],
- idx.node, &(*substs))
+ base_def.struct_variant()
+ .fields
+ .get(idx.node)
+ .map(|f| fcx.field_ty(expr.span, f, substs))
} else {
None
}
fcx.write_error(expr.id);
}
- fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- adt_ty: Ty<'tcx>,
- span: Span,
- variant_id: ast::DefId,
- substitutions: &'tcx subst::Substs<'tcx>,
- field_types: &[ty::FieldTy],
- ast_fields: &'tcx [ast::Field],
- check_completeness: bool) -> Result<(),()> {
+ fn report_unknown_field<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ ty: Ty<'tcx>,
+ variant: ty::VariantDef<'tcx>,
+ field: &ast::Field,
+ skip_fields: &[ast::Field]) {
+ fcx.type_error_message(
+ field.ident.span,
+ |actual| if let ty::TyEnum(..) = ty.sty {
+ format!("struct variant `{}::{}` has no field named `{}`",
+ actual, variant.name.as_str(), field.ident.node)
+ } else {
+ format!("structure `{}` has no field named `{}`",
+ actual, field.ident.node)
+ },
+ ty,
+ None);
+ // prevent all specified fields from being suggested
+ let skip_fields = skip_fields.iter().map(|ref x| x.ident.node.name.as_str());
+ suggest_field_names(variant, &field.ident, fcx.tcx(), skip_fields.collect());
+ }
+
+
+ fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ adt_ty: Ty<'tcx>,
+ span: Span,
+ variant: ty::VariantDef<'tcx>,
+ ast_fields: &'tcx [ast::Field],
+ check_completeness: bool) {
let tcx = fcx.ccx.tcx;
- let (adt_def, is_enum) = match adt_ty.sty {
- ty::TyStruct(def, _) => (def, false),
- ty::TyEnum(def, _) => (def, true),
- _ => tcx.sess.span_bug(span, "non-ADT passed to check_struct_or_variant_fields")
+ let substs = match adt_ty.sty {
+ ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
+ _ => tcx.sess.span_bug(span, "non-ADT passed to check_expr_struct_fields")
};
- let mut class_field_map = FnvHashMap();
- let mut fields_found = 0;
- for field in field_types {
- class_field_map.insert(field.name, (field.id, false));
+ let mut remaining_fields = FnvHashMap();
+ for field in &variant.fields {
+ remaining_fields.insert(field.name, field);
}
let mut error_happened = false;
// Typecheck each field.
for field in ast_fields {
- let mut expected_field_type = tcx.types.err;
-
- let pair = class_field_map.get(&field.ident.node.name).cloned();
- match pair {
- None => {
- fcx.type_error_message(
- field.ident.span,
- |actual| if is_enum {
- let variant_type = tcx.enum_variant_with_id(adt_def.did,
- variant_id);
- format!("struct variant `{}::{}` has no field named `{}`",
- actual, variant_type.name.as_str(),
- field.ident.node)
- } else {
- format!("structure `{}` has no field named `{}`",
- actual,
- field.ident.node)
- },
- adt_ty,
- None);
- // prevent all specified fields from being suggested
- let skip_fields = ast_fields.iter().map(|ref x| x.ident.node.name.as_str());
- suggest_field_names(variant_id, &field.ident, tcx, skip_fields.collect());
- error_happened = true;
- }
- Some((_, true)) => {
+ let expected_field_type;
+
+ if let Some(v_field) = remaining_fields.remove(&field.ident.node.name) {
+ expected_field_type = fcx.field_ty(field.span, v_field, substs);
+ } else {
+ error_happened = true;
+ expected_field_type = tcx.types.err;
+ if let Some(_) = variant.find_field_named(field.ident.node.name) {
span_err!(fcx.tcx().sess, field.ident.span, E0062,
"field `{}` specified more than once",
field.ident.node);
- error_happened = true;
- }
- Some((field_id, false)) => {
- expected_field_type =
- tcx.lookup_field_type(variant_id, field_id, substitutions);
- expected_field_type =
- fcx.normalize_associated_types_in(
- field.span, &expected_field_type);
- class_field_map.insert(
- field.ident.node.name, (field_id, true));
- fields_found += 1;
+ } else {
+ report_unknown_field(fcx, adt_ty, variant, field, ast_fields);
}
}
check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type);
}
- if check_completeness && !error_happened {
// Make sure the programmer specified all the fields.
- assert!(fields_found <= field_types.len());
- if fields_found < field_types.len() {
- let mut missing_fields = Vec::new();
- for class_field in field_types {
- let name = class_field.name;
- let (_, seen) = *class_field_map.get(&name).unwrap();
- if !seen {
- missing_fields.push(
- format!("`{}`", name))
- }
- }
-
- span_err!(tcx.sess, span, E0063,
- "missing field{}: {}",
- if missing_fields.len() == 1 {""} else {"s"},
- missing_fields.join(", "));
- }
- }
-
- if error_happened { Err(()) } else { Ok(()) }
- }
-
- fn check_struct_constructor<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
- id: ast::NodeId,
- span: codemap::Span,
- struct_def: &'tcx ty::ADTDef<'tcx>,
- fields: &'tcx [ast::Field],
- base_expr: Option<&'tcx ast::Expr>) {
- let tcx = fcx.ccx.tcx;
-
- // Generate the struct type.
- let TypeAndSubsts {
- ty: mut struct_type,
- substs: struct_substs
- } = fcx.instantiate_type(span, struct_def.did);
-
- // Look up and check the fields.
- let class_fields = tcx.lookup_struct_fields(struct_def.did);
- let res = check_struct_or_variant_fields(fcx,
- struct_type,
- span,
- struct_def.did,
- fcx.ccx.tcx.mk_substs(struct_substs),
- &class_fields[..],
- fields,
- base_expr.is_none());
- if res.is_err() {
- struct_type = tcx.types.err;
- }
-
- // Check the base expression if necessary.
- match base_expr {
- None => {}
- Some(base_expr) => {
- check_expr_has_type(fcx, &*base_expr, struct_type);
- }
+ if check_completeness &&
+ !error_happened &&
+ !remaining_fields.is_empty()
+ {
+ span_err!(tcx.sess, span, E0063,
+ "missing field{}: {}",
+ if remaining_fields.len() == 1 {""} else {"s"},
+ remaining_fields.keys()
+ .map(|n| format!("`{}`", n))
+ .collect::<Vec<_>>()
+ .join(", "));
}
-
- // Write in the resulting type.
- fcx.write_ty(id, struct_type);
- }
-
- fn check_struct_enum_variant<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
- id: ast::NodeId,
- span: codemap::Span,
- enum_id: ast::DefId,
- variant_id: ast::DefId,
- fields: &'tcx [ast::Field]) {
- let tcx = fcx.ccx.tcx;
-
- // Look up the number of type parameters and the raw type, and
- // determine whether the enum is region-parameterized.
- let TypeAndSubsts {
- ty: enum_type,
- substs: substitutions
- } = fcx.instantiate_type(span, enum_id);
-
- // Look up and check the enum variant fields.
- let variant_fields = tcx.lookup_struct_fields(variant_id);
- let _ = check_struct_or_variant_fields(fcx,
- enum_type,
- span,
- variant_id,
- fcx.ccx.tcx.mk_substs(substitutions),
- &variant_fields[..],
- fields,
- true);
- fcx.write_ty(id, enum_type);
}
fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
}
}
+ fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>,
+ expr: &ast::Expr,
+ path: &ast::Path,
+ fields: &'tcx [ast::Field],
+ base_expr: &'tcx Option<P<ast::Expr>>)
+ {
+ let tcx = fcx.tcx();
+
+ // Find the relevant variant
+ let def = lookup_full_def(tcx, path.span, expr.id);
+ let (adt, variant) = match fcx.def_struct_variant(def) {
+ Some((adt, variant)) => (adt, variant),
+ None => {
+ span_err!(fcx.tcx().sess, path.span, E0071,
+ "`{}` does not name a structure",
+ pprust::path_to_string(path));
+ check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
+ return;
+ }
+ };
+
+ let expr_ty = fcx.instantiate_type(def.def_id(), path);
+ fcx.write_ty(expr.id, expr_ty);
+
+ check_expr_struct_fields(fcx, expr_ty, expr.span, variant, fields,
+ base_expr.is_none());
+
+ if let &Some(ref base_expr) = base_expr {
+ check_expr_has_type(fcx, base_expr, expr_ty);
+ if adt.adt_kind() == ty::AdtKind::Enum {
+ span_err!(tcx.sess, base_expr.span, E0436,
+ "functional record update syntax requires a struct");
+ }
+ }
+ }
+
type ExprCheckerWithTy = fn(&FnCtxt, &ast::Expr, Ty);
let tcx = fcx.ccx.tcx;
// We always require that the type provided as the value for
// a type parameter outlives the moment of instantiation.
- constrain_path_type_parameters(fcx, expr);
+ fcx.opt_node_ty_substs(expr.id, |item_substs| {
+ fcx.add_wf_bounds(&item_substs.substs, expr);
+ });
}
ast::ExprInlineAsm(ref ia) => {
for &(_, ref input) in &ia.inputs {
}
ast::ExprCall(ref callee, ref args) => {
callee::check_call(fcx, expr, &**callee, &args[..], expected);
+
+ // we must check that return type of called functions is WF:
+ let ret_ty = fcx.expr_ty(expr);
+ fcx.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
}
ast::ExprMethodCall(ident, ref tps, ref args) => {
- check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref);
- let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
- let args_err = arg_tys.fold(false,
- |rest_err, a| {
- rest_err || a.references_error()});
- if args_err {
- fcx.write_error(id);
- }
+ check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref);
+ let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
+ let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
+ if args_err {
+ fcx.write_error(id);
+ }
}
ast::ExprCast(ref e, ref t) => {
if let ast::TyFixedLengthVec(_, ref count_expr) = t.node {
}
}
ast::ExprStruct(ref path, ref fields, ref base_expr) => {
- // Resolve the path.
- let def = lookup_full_def(tcx, path.span, id);
- let struct_id = match def {
- def::DefVariant(enum_id, variant_id, true) => {
- if let &Some(ref base_expr) = base_expr {
- span_err!(tcx.sess, base_expr.span, E0436,
- "functional record update syntax requires a struct");
- fcx.write_error(base_expr.id);
- }
- check_struct_enum_variant(fcx, id, expr.span, enum_id,
- variant_id, &fields[..]);
- enum_id
- }
- def::DefTrait(def_id) => {
- span_err!(tcx.sess, path.span, E0159,
- "use of trait `{}` as a struct constructor",
- pprust::path_to_string(path));
- check_struct_fields_on_error(fcx,
- id,
- &fields[..],
- base_expr);
- def_id
- },
- def => {
- // Verify that this was actually a struct.
- let typ = fcx.ccx.tcx.lookup_item_type(def.def_id());
- match typ.ty.sty {
- ty::TyStruct(struct_def, _) => {
- check_struct_constructor(fcx,
- id,
- expr.span,
- struct_def,
- &fields[..],
- base_expr.as_ref().map(|e| &**e));
- }
- _ => {
- span_err!(tcx.sess, path.span, E0071,
- "`{}` does not name a structure",
- pprust::path_to_string(path));
- check_struct_fields_on_error(fcx,
- id,
- &fields[..],
- base_expr);
- }
- }
-
- def.def_id()
- }
- };
-
- // Turn the path into a type and verify that that type unifies with
- // the resulting structure type. This is needed to handle type
- // parameters correctly.
- let actual_structure_type = fcx.expr_ty(&*expr);
- if !actual_structure_type.references_error() {
- let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path);
- match fcx.mk_subty(false,
- infer::Misc(path.span),
- actual_structure_type,
- type_and_substs.ty) {
- Ok(()) => {}
- Err(type_error) => {
- span_err!(fcx.tcx().sess, path.span, E0235,
- "structure constructor specifies a \
- structure of type `{}`, but this \
- structure has type `{}`: {}",
- fcx.infcx()
- .ty_to_string(type_and_substs.ty),
- fcx.infcx()
- .ty_to_string(
- actual_structure_type),
- type_error);
- tcx.note_and_explain_type_err(&type_error, path.span);
- }
- }
- }
-
+ check_expr_struct(fcx, expr, path, fields, base_expr);
fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized);
}
ast::ExprField(ref base, ref field) => {
}
}
-fn constrain_path_type_parameters(fcx: &FnCtxt,
- expr: &ast::Expr)
-{
- fcx.opt_node_ty_substs(expr.id, |item_substs| {
- fcx.add_default_region_param_bounds(&item_substs.substs, expr);
- });
-}
-
impl<'tcx> Expectation<'tcx> {
/// Provide an expectation for an rvalue expression given an *optional*
/// hint, which is not required for type safety (the resulting type might
}
match t.sty {
ty::TyStruct(def, substs) => {
- let fields = tcx.lookup_struct_fields(def.did);
+ let fields = &def.struct_variant().fields;
if fields.is_empty() {
span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty");
return;
}
- let e = tcx.lookup_field_type(def.did, fields[0].id, substs);
- if !fields.iter().all(
- |f| tcx.lookup_field_type(def.did, f.id, substs) == e) {
+ let e = fields[0].ty(tcx, substs);
+ if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous");
return;
}
let def_id = local_def(id);
- // ty::enum_variants guards against discriminant overflows, so
- // we need not check for that.
- let variants = ccx.tcx.enum_variants(def_id);
-
+ let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
for (v, variant) in vs.iter().zip(variants.iter()) {
let current_disr_val = variant.disr_val;
Some(i) => {
span_err!(ccx.tcx.sess, v.span, E0081,
"discriminant value `{}` already exists", disr_vals[i]);
- span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].id.node),
+ span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].did.node),
"conflicting discriminant here")
}
None => {}
}
}
+ debug!("instantiate_path: type of {:?} is {:?}",
+ node_id,
+ ty_substituted);
fcx.write_ty(node_id, ty_substituted);
fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
return;