use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::infer;
-use middle::infer::{TypeOrigin, type_variable};
+use middle::infer::{TypeOrigin, TypeTrace, type_variable};
use middle::pat_util::{self, pat_id_map};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
-use middle::traits::{self, report_fulfillment_errors};
+use middle::traits::{self, report_fulfillment_errors, ProjectionMode};
use middle::ty::{GenericPredicates, TypeScheme};
-use middle::ty::{Disr, ParamTy, ParameterEnvironment};
+use middle::ty::{ParamTy, ParameterEnvironment};
use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
use middle::ty::{MethodCall, MethodCallee};
use middle::ty::adjustment;
use middle::ty::error::TypeError;
use middle::ty::fold::{TypeFolder, TypeFoldable};
-use middle::ty::util::Representability;
+use middle::ty::relate::TypeRelation;
+use middle::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
use session::{Session, CompileResult};
-> Inherited<'a, 'tcx> {
Inherited {
- infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env)),
+ infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), ProjectionMode::AnyFinal),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
locals: RefCell::new(NodeMap()),
tables: tables,
param_env: ty::ParameterEnvironment<'a, 'tcx>)
{
match raw_fty.sty {
- ty::TyBareFn(_, ref fn_ty) => {
+ ty::TyFnDef(_, _, ref fn_ty) => {
let tables = RefCell::new(ty::Tables::empty());
let inh = Inherited::new(ccx.tcx, &tables, param_env);
hir::ItemFn(..) => {} // entirely within check_item_body
hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
debug!("ItemImpl {} with id {}", it.name, it.id);
- match ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(it.id)) {
+ let impl_def_id = ccx.tcx.map.local_def_id(it.id);
+ match ccx.tcx.impl_trait_ref(impl_def_id) {
Some(impl_trait_ref) => {
check_impl_items_against_trait(ccx,
it.span,
+ impl_def_id,
&impl_trait_ref,
impl_items);
}
check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
}
+fn report_forbidden_specialization(tcx: &TyCtxt,
+ impl_item: &hir::ImplItem,
+ parent_impl: DefId)
+{
+ let mut err = struct_span_err!(
+ tcx.sess, impl_item.span, E0520,
+ "item `{}` is provided by an `impl` that specializes \
+ another, but the item in the parent `impl` is not \
+ marked `default` and so it cannot be specialized.",
+ impl_item.name);
+
+ match tcx.span_of_impl(parent_impl) {
+ Ok(span) => {
+ err.span_note(span, "parent implementation is here:");
+ }
+ Err(cname) => {
+ err.note(&format!("parent implementation is in crate `{}`", cname));
+ }
+ }
+
+ err.emit();
+}
+
+fn check_specialization_validity<'tcx>(tcx: &TyCtxt<'tcx>, trait_def: &ty::TraitDef<'tcx>,
+ impl_id: DefId, impl_item: &hir::ImplItem)
+{
+ let ancestors = trait_def.ancestors(impl_id);
+
+ let parent = match impl_item.node {
+ hir::ImplItemKind::Const(..) => {
+ ancestors.const_defs(tcx, impl_item.name).skip(1).next()
+ .map(|node_item| node_item.map(|parent| parent.defaultness))
+ }
+ hir::ImplItemKind::Method(..) => {
+ ancestors.fn_defs(tcx, impl_item.name).skip(1).next()
+ .map(|node_item| node_item.map(|parent| parent.defaultness))
+
+ }
+ hir::ImplItemKind::Type(_) => {
+ ancestors.type_defs(tcx, impl_item.name).skip(1).next()
+ .map(|node_item| node_item.map(|parent| parent.defaultness))
+ }
+ };
+
+ if let Some(parent) = parent {
+ if parent.item.is_final() {
+ report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
+ }
+ }
+
+}
+
fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
impl_span: Span,
+ impl_id: DefId,
impl_trait_ref: &ty::TraitRef<'tcx>,
impl_items: &[hir::ImplItem]) {
- // Locate trait methods
+ // If the trait reference itself is erroneous (so the compilation is going
+ // to fail), skip checking the items here -- the `impl_item` table in `tcx`
+ // isn't populated for such impls.
+ if impl_trait_ref.references_error() { return; }
+
+ // Locate trait definition and items
let tcx = ccx.tcx;
+ let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
let trait_items = tcx.trait_items(impl_trait_ref.def_id);
let mut overridden_associated_type = None;
let ty_trait_item = trait_items.iter()
.find(|ac| ac.name() == ty_impl_item.name());
+ // Check that impl definition matches trait definition
if let Some(ty_trait_item) = ty_trait_item {
match impl_item.node {
hir::ImplItemKind::Const(..) => {
}
}
}
+
+ check_specialization_validity(tcx, trait_def, impl_id, impl_item);
}
// Check for missing items from trait
let mut invalidated_items = Vec::new();
let associated_type_overridden = overridden_associated_type.is_some();
for trait_item in trait_items.iter() {
+ let is_implemented;
+ let is_provided;
+
match *trait_item {
ty::ConstTraitItem(ref associated_const) => {
- let is_implemented = impl_items.iter().any(|ii| {
+ is_provided = associated_const.has_value;
+ is_implemented = impl_items.iter().any(|ii| {
match ii.node {
hir::ImplItemKind::Const(..) => {
ii.name == associated_const.name
_ => false,
}
});
- let is_provided = associated_const.has_value;
-
- if !is_implemented {
- if !is_provided {
- missing_items.push(associated_const.name);
- } else if associated_type_overridden {
- invalidated_items.push(associated_const.name);
- }
- }
}
ty::MethodTraitItem(ref trait_method) => {
- let is_implemented =
- impl_items.iter().any(|ii| {
- match ii.node {
- hir::ImplItemKind::Method(..) => {
- ii.name == trait_method.name
- }
- _ => false,
- }
- });
- let is_provided =
- provided_methods.iter().any(|m| m.name == trait_method.name);
- if !is_implemented {
- if !is_provided {
- missing_items.push(trait_method.name);
- } else if associated_type_overridden {
- invalidated_items.push(trait_method.name);
- }
- }
+ is_provided = provided_methods.iter().any(|m| m.name == trait_method.name);
+ is_implemented = trait_def.ancestors(impl_id)
+ .fn_defs(tcx, trait_method.name)
+ .next()
+ .map(|node_item| !node_item.node.is_from_trait())
+ .unwrap_or(false);
}
- ty::TypeTraitItem(ref associated_type) => {
- let is_implemented = impl_items.iter().any(|ii| {
- match ii.node {
- hir::ImplItemKind::Type(_) => {
- ii.name == associated_type.name
- }
- _ => false,
- }
- });
- let is_provided = associated_type.ty.is_some();
- if !is_implemented {
- if !is_provided {
- missing_items.push(associated_type.name);
- } else if associated_type_overridden {
- invalidated_items.push(associated_type.name);
- }
- }
+ ty::TypeTraitItem(ref trait_assoc_ty) => {
+ is_provided = trait_assoc_ty.ty.is_some();
+ is_implemented = trait_def.ancestors(impl_id)
+ .type_defs(tcx, trait_assoc_ty.name)
+ .next()
+ .map(|node_item| !node_item.node.is_from_trait())
+ .unwrap_or(false);
+ }
+ }
+
+ if !is_implemented {
+ if !is_provided {
+ missing_items.push(trait_item.name());
+ } else if associated_type_overridden {
+ invalidated_items.push(trait_item.name());
}
}
}
self.infcx().type_error_struct(sp, mk_msg, actual_ty, err)
}
- pub fn report_mismatched_types(&self,
- sp: Span,
- e: Ty<'tcx>,
- a: Ty<'tcx>,
- err: &TypeError<'tcx>) {
- self.infcx().report_mismatched_types(sp, e, a, err)
- }
-
/// Registers an obligation for checking later, during regionck, that the type `ty` must
/// outlive the region `r`.
pub fn register_region_obligation(&self,
}
// FIXME(arielb1): use this instead of field.ty everywhere
+ // Only for fields! Returns <none> for methods>
+ // Indifferent to privacy flags
pub fn field_ty(&self,
span: Span,
field: ty::FieldDef<'tcx>,
&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(..) {
///
/// Note: this method does not modify the adjustments table. The caller is responsible for
/// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods.
-pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
- sp: Span,
- base_ty: Ty<'tcx>,
- opt_expr: Option<&hir::Expr>,
- unresolved_type_action: UnresolvedTypeAction,
- mut lvalue_pref: LvaluePreference,
- mut should_stop: F)
- -> (Ty<'tcx>, usize, Option<T>)
- where F: FnMut(Ty<'tcx>, usize) -> Option<T>,
+pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>,
+ sp: Span,
+ base_ty: Ty<'tcx>,
+ maybe_exprs: E,
+ unresolved_type_action: UnresolvedTypeAction,
+ mut lvalue_pref: LvaluePreference,
+ mut should_stop: F)
+ -> (Ty<'tcx>, usize, Option<T>)
+ // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+ where E: Fn() -> I,
+ I: IntoIterator<Item=&'b hir::Expr>,
+ F: FnMut(Ty<'tcx>, usize) -> Option<T>,
{
- debug!("autoderef(base_ty={:?}, opt_expr={:?}, lvalue_pref={:?})",
- base_ty,
- opt_expr,
- lvalue_pref);
+ debug!("autoderef(base_ty={:?}, lvalue_pref={:?})",
+ base_ty, lvalue_pref);
let mut t = base_ty;
for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() {
// (i.e. it is an inference variable) because `Ty::builtin_deref`
// and `try_overloaded_deref` both simply return `None`
// in such a case without producing spurious errors.
- fcx.resolve_type_vars_if_possible(t)
+ fcx.infcx().resolve_type_vars_if_possible(&t)
}
};
if resolved_t.references_error() {
}
// Otherwise, deref if type is derefable:
- let mt = match resolved_t.builtin_deref(false, lvalue_pref) {
- Some(mt) => Some(mt),
- None => {
- let method_call =
- opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32));
-
- // Super subtle: it might seem as though we should
- // pass `opt_expr` to `try_overloaded_deref`, so that
- // the (implicit) autoref of using an overloaded deref
- // would get added to the adjustment table. However we
- // do not do that, because it's kind of a
- // "meta-adjustment" -- instead, we just leave it
- // unrecorded and know that there "will be" an
- // autoref. regionck and other bits of the code base,
- // when they encounter an overloaded autoderef, have
- // to do some reconstructive surgery. This is a pretty
- // complex mess that is begging for a proper MIR.
- try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
+
+ // Super subtle: it might seem as though we should
+ // pass `opt_expr` to `try_overloaded_deref`, so that
+ // the (implicit) autoref of using an overloaded deref
+ // would get added to the adjustment table. However we
+ // do not do that, because it's kind of a
+ // "meta-adjustment" -- instead, we just leave it
+ // unrecorded and know that there "will be" an
+ // autoref. regionck and other bits of the code base,
+ // when they encounter an overloaded autoderef, have
+ // to do some reconstructive surgery. This is a pretty
+ // complex mess that is begging for a proper MIR.
+ let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) {
+ mt
+ } else if let Some(method) = try_overloaded_deref(fcx, sp, None,
+ resolved_t, lvalue_pref) {
+ for expr in maybe_exprs() {
+ let method_call = MethodCall::autoderef(expr.id, autoderefs as u32);
+ fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
}
+ make_overloaded_lvalue_return_type(fcx.tcx(), method)
+ } else {
+ return (resolved_t, autoderefs, None);
};
- match mt {
- Some(mt) => {
- t = mt.ty;
- if mt.mutbl == hir::MutImmutable {
- lvalue_pref = NoPreference;
- }
- }
- None => return (resolved_t, autoderefs, None)
+
+ t = mt.ty;
+ if mt.mutbl == hir::MutImmutable {
+ lvalue_pref = NoPreference;
}
}
fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
- method_call: Option<MethodCall>,
base_expr: Option<&hir::Expr>,
base_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference)
- -> Option<ty::TypeAndMut<'tcx>>
+ -> Option<MethodCallee<'tcx>>
{
// Try DerefMut first, if preferred.
let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
(method, _) => method
};
- make_overloaded_lvalue_return_type(fcx, method_call, method)
+ method
}
/// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the
/// actual type we assign to the *expression* is `T`. So this function just peels off the return
-/// type by one layer to yield `T`. It also inserts the `method-callee` into the method map.
-fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- method_call: Option<MethodCall>,
- method: Option<MethodCallee<'tcx>>)
- -> Option<ty::TypeAndMut<'tcx>>
+/// type by one layer to yield `T`.
+fn make_overloaded_lvalue_return_type<'tcx>(tcx: &TyCtxt<'tcx>,
+ method: MethodCallee<'tcx>)
+ -> ty::TypeAndMut<'tcx>
{
- match method {
- Some(method) => {
- // extract method return type, which will be &T;
- // all LB regions should have been instantiated during method lookup
- let ret_ty = method.ty.fn_ret();
- let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap();
-
- if let Some(method_call) = method_call {
- fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
- }
+ // extract method return type, which will be &T;
+ // all LB regions should have been instantiated during method lookup
+ let ret_ty = method.ty.fn_ret();
+ let ret_ty = tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
- // method returns &T, but the type as visible to user is T, so deref
- ret_ty.builtin_deref(true, NoPreference)
- }
- None => None,
- }
+ // method returns &T, but the type as visible to user is T, so deref
+ ret_ty.builtin_deref(true, NoPreference).unwrap()
}
fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
let (ty, autoderefs, final_mt) = autoderef(fcx,
base_expr.span,
base_ty,
- Some(base_expr),
+ || Some(base_expr),
UnresolvedTypeAction::Error,
lvalue_pref,
|adj_ty, idx| {
// If some lookup succeeds, write callee into table and extract index/element
// type from the method signature.
// If some lookup succeeded, install method in table
- method.and_then(|method| {
+ method.map(|method| {
debug!("try_index_step: success, using overloaded indexing");
- make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method)).
- map(|ret| (input_ty, ret.ty))
+ fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
+ (input_ty, make_overloaded_lvalue_return_type(fcx.tcx(), method).ty)
})
}
ty::FnConverging(fcx.tcx().types.err)
} else {
match method_fn_ty.sty {
- ty::TyBareFn(_, ref fty) => {
+ ty::TyFnDef(_, _, ref fty) => {
// HACK(eddyb) ignore self in the definition (see above).
let expected_arg_tys = expected_types_for_fn_args(fcx,
sp,
Expectation::rvalue_hint(fcx.tcx(), ty)
});
- check_expr_with_unifier(fcx,
- &arg,
- expected.unwrap_or(ExpectHasType(formal_ty)),
- NoPreference, || {
- // 2. Coerce to the most detailed type that could be coerced
- // to, which is `expected_ty` if `rvalue_hint` returns an
- // `ExprHasType(expected_ty)`, or the `formal_ty` otherwise.
- let coerce_ty = expected.and_then(|e| e.only_has_type(fcx));
- demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg);
-
- // 3. Relate the expected type and the formal one,
- // if the expected type was used for the coercion.
- coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty));
- });
+ check_expr_with_expectation(fcx, &arg,
+ expected.unwrap_or(ExpectHasType(formal_ty)));
+ // 2. Coerce to the most detailed type that could be coerced
+ // to, which is `expected_ty` if `rvalue_hint` returns an
+ // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+ let coerce_ty = expected.and_then(|e| e.only_has_type(fcx));
+ demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg);
+
+ // 3. Relate the expected type and the formal one,
+ // if the expected type was used for the coercion.
+ coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty));
}
if let Some(&arg_ty) = fcx.inh.tables.borrow().node_types.get(&arg.id) {
ty::TyInt(_) | ty::TyUint(_) => Some(ty),
ty::TyChar => Some(tcx.types.u8),
ty::TyRawPtr(..) => Some(tcx.types.usize),
- ty::TyBareFn(..) => Some(tcx.types.usize),
+ ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize),
_ => None
}
});
fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr,
expected: Ty<'tcx>) {
- check_expr_with_unifier(
- fcx, expr, ExpectHasType(expected), NoPreference,
- || demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr)));
+ check_expr_with_hint(fcx, expr, expected);
+ demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr));
}
pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr,
expected: Ty<'tcx>) {
- check_expr_with_unifier(
- fcx, expr, ExpectHasType(expected), NoPreference,
- || demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr)));
+ check_expr_with_hint(fcx, expr, expected);
+ demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr));
}
fn check_expr_coercable_to_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr,
expected: Ty<'tcx>) {
- check_expr_with_unifier(
- fcx, expr, ExpectHasType(expected), NoPreference,
- || demand::coerce(fcx, expr.span, expected, expr));
+ check_expr_with_hint(fcx, expr, expected);
+ demand::coerce(fcx, expr.span, expected, expr);
}
fn check_expr_with_hint<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr,
expected: Ty<'tcx>) {
- check_expr_with_unifier(
- fcx, expr, ExpectHasType(expected), NoPreference,
- || ())
+ check_expr_with_expectation(fcx, expr, ExpectHasType(expected))
}
fn check_expr_with_expectation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr,
expected: Expectation<'tcx>) {
- check_expr_with_unifier(
- fcx, expr, expected, NoPreference,
- || ())
-}
-
-fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- expr: &'tcx hir::Expr,
- expected: Expectation<'tcx>,
- lvalue_pref: LvaluePreference)
-{
- check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ())
+ check_expr_with_expectation_and_lvalue_pref(fcx, expr, expected, NoPreference)
}
fn check_expr<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr) {
- check_expr_with_unifier(fcx, expr, NoExpectation, NoPreference, || ())
+ check_expr_with_expectation(fcx, expr, NoExpectation)
}
fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr,
lvalue_pref: LvaluePreference) {
- check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ())
+ check_expr_with_expectation_and_lvalue_pref(fcx, expr, NoExpectation, lvalue_pref)
}
// determine the `self` type, using fresh variables for all variables
/// Note that inspecting a type's structure *directly* may expose the fact
/// that there are actually multiple representations for `TyError`, so avoid
/// that when err needs to be handled differently.
-fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
- expr: &'tcx hir::Expr,
- expected: Expectation<'tcx>,
- lvalue_pref: LvaluePreference,
- unifier: F) where
- F: FnOnce(),
-{
+fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ expr: &'tcx hir::Expr,
+ expected: Expectation<'tcx>,
+ lvalue_pref: LvaluePreference) {
debug!(">> typechecking: expr={:?} expected={:?}",
expr, expected);
check_block_with_expected(fcx, then_blk, expected);
let then_ty = fcx.node_ty(then_blk.id);
- let branches_ty = match opt_else_expr {
- Some(ref else_expr) => {
- check_expr_with_expectation(fcx, &else_expr, expected);
- let else_ty = fcx.expr_ty(&else_expr);
- infer::common_supertype(fcx.infcx(),
- TypeOrigin::IfExpression(sp),
- true,
- then_ty,
- else_ty)
- }
- None => {
- infer::common_supertype(fcx.infcx(),
- TypeOrigin::IfExpressionWithNoElse(sp),
- false,
- then_ty,
- fcx.tcx().mk_nil())
- }
- };
+ let unit = fcx.tcx().mk_nil();
+ let (origin, expected, found, result) =
+ if let Some(else_expr) = opt_else_expr {
+ check_expr_with_expectation(fcx, else_expr, expected);
+ let else_ty = fcx.expr_ty(else_expr);
+ let origin = TypeOrigin::IfExpression(sp);
+
+ // Only try to coerce-unify if we have a then expression
+ // to assign coercions to, otherwise it's () or diverging.
+ let result = if let Some(ref then) = then_blk.expr {
+ let res = coercion::try_find_lub(fcx, origin, || Some(&**then),
+ then_ty, else_expr);
+
+ // In case we did perform an adjustment, we have to update
+ // the type of the block, because old trans still uses it.
+ let adj = fcx.inh.tables.borrow().adjustments.get(&then.id).cloned();
+ if res.is_ok() && adj.is_some() {
+ fcx.write_ty(then_blk.id, fcx.adjust_expr_ty(then, adj.as_ref()));
+ }
- let cond_ty = fcx.expr_ty(cond_expr);
- let if_ty = if cond_ty.references_error() {
- fcx.tcx().types.err
+ res
+ } else {
+ fcx.infcx().commit_if_ok(|_| {
+ let trace = TypeTrace::types(origin, true, then_ty, else_ty);
+ fcx.infcx().lub(true, trace).relate(&then_ty, &else_ty)
+ })
+ };
+ (origin, then_ty, else_ty, result)
} else {
- branches_ty
+ let origin = TypeOrigin::IfExpressionWithNoElse(sp);
+ (origin, unit, then_ty,
+ fcx.infcx().eq_types(true, origin, unit, then_ty).map(|_| unit))
+ };
+
+ let if_ty = match result {
+ Ok(ty) => {
+ if fcx.expr_ty(cond_expr).references_error() {
+ fcx.tcx().types.err
+ } else {
+ ty
+ }
+ }
+ Err(e) => {
+ fcx.infcx().report_mismatched_types(origin, expected, found, e);
+ fcx.tcx().types.err
+ }
};
fcx.write_ty(id, if_ty);
let (_, autoderefs, field_ty) = autoderef(fcx,
expr.span,
expr_t,
- Some(base),
+ || Some(base),
UnresolvedTypeAction::Error,
lvalue_pref,
|base_t, _| {
let (_, autoderefs, field_ty) = autoderef(fcx,
expr.span,
expr_t,
- Some(base),
+ || Some(base),
UnresolvedTypeAction::Error,
lvalue_pref,
|base_t, _| {
match unop {
hir::UnDeref => {
oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
- oprnd_t = match oprnd_t.builtin_deref(true, NoPreference) {
- Some(mt) => mt.ty,
- None => match try_overloaded_deref(fcx, expr.span,
- Some(MethodCall::expr(expr.id)),
- Some(&oprnd), oprnd_t, lvalue_pref) {
- Some(mt) => mt.ty,
- None => {
- fcx.type_error_message(expr.span, |actual| {
- format!("type `{}` cannot be \
- dereferenced", actual)
- }, oprnd_t, None);
- tcx.types.err
- }
- }
- };
+
+ if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) {
+ oprnd_t = mt.ty;
+ } else if let Some(method) = try_overloaded_deref(
+ fcx, expr.span, Some(&oprnd), oprnd_t, lvalue_pref) {
+ oprnd_t = make_overloaded_lvalue_return_type(tcx, method).ty;
+ fcx.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id),
+ method);
+ } else {
+ fcx.type_error_message(expr.span, |actual| {
+ format!("type `{}` cannot be \
+ dereferenced", actual)
+ }, oprnd_t, None);
+ oprnd_t = tcx.types.err;
+ }
}
hir::UnNot => {
oprnd_t = structurally_resolved_type(fcx, oprnd.span,
fcx.add_wf_bounds(&item_substs.substs, expr);
});
}
- hir::ExprInlineAsm(ref ia) => {
- for &(_, ref input) in &ia.inputs {
- check_expr(fcx, &input);
+ hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
+ for output in outputs {
+ check_expr(fcx, output);
}
- for out in &ia.outputs {
- check_expr(fcx, &out.expr);
+ for input in inputs {
+ check_expr(fcx, input);
}
fcx.write_nil(id);
}
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
- let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span);
+ let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span);
deferred_cast_checks.push(cast_check);
}
}
}
});
- let typ = match uty {
- Some(uty) => {
- for e in args {
- check_expr_coercable_to_type(fcx, &e, uty);
- }
- uty
- }
- None => {
- let t: Ty = fcx.infcx().next_ty_var();
- for e in args {
- check_expr_has_type(fcx, &e, t);
+ let mut unified = fcx.infcx().next_ty_var();
+ let coerce_to = uty.unwrap_or(unified);
+
+ for (i, e) in args.iter().enumerate() {
+ check_expr_with_hint(fcx, e, coerce_to);
+ let e_ty = fcx.expr_ty(e);
+ let origin = TypeOrigin::Misc(e.span);
+
+ // Special-case the first element, as it has no "previous expressions".
+ let result = if i == 0 {
+ coercion::try(fcx, e, coerce_to)
+ } else {
+ let prev_elems = || args[..i].iter().map(|e| &**e);
+ coercion::try_find_lub(fcx, origin, prev_elems, unified, e)
+ };
+
+ match result {
+ Ok(ty) => unified = ty,
+ Err(e) => {
+ fcx.infcx().report_mismatched_types(origin, unified, e_ty, e);
}
- t
}
- };
- let typ = tcx.mk_array(typ, args.len());
- fcx.write_ty(id, typ);
+ }
+ fcx.write_ty(id, tcx.mk_array(unified, args.len()));
}
hir::ExprRepeat(ref element, ref count_expr) => {
check_expr_has_type(fcx, &count_expr, tcx.types.usize);
debug!("... {:?}, expected is {:?}",
fcx.expr_ty(expr),
expected);
-
- unifier();
}
pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
sp: Span,
vs: &'tcx [hir::Variant],
id: ast::NodeId) {
- // disr_in_range should be removed once we have forced type hints for consts
- fn disr_in_range(ccx: &CrateCtxt,
- ty: attr::IntType,
- disr: ty::Disr) -> bool {
- fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
- match ty {
- ast::UintTy::U8 => disr as u8 as Disr == disr,
- ast::UintTy::U16 => disr as u16 as Disr == disr,
- ast::UintTy::U32 => disr as u32 as Disr == disr,
- ast::UintTy::U64 => disr as u64 as Disr == disr,
- ast::UintTy::Us => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
- }
- }
- fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
- match ty {
- ast::IntTy::I8 => disr as i8 as Disr == disr,
- ast::IntTy::I16 => disr as i16 as Disr == disr,
- ast::IntTy::I32 => disr as i32 as Disr == disr,
- ast::IntTy::I64 => disr as i64 as Disr == disr,
- ast::IntTy::Is => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
- }
- }
- match ty {
- attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
- attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
- }
- }
-
fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
vs: &'tcx [hir::Variant],
id: ast::NodeId,
let inh = static_inherited_fields(ccx, &tables);
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
- let (_, repr_type_ty) = ccx.tcx.enum_repr_type(Some(&hint));
+ let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(&ccx.tcx);
for v in vs {
if let Some(ref e) = v.node.disr_expr {
check_const_with_ty(&fcx, e.span, e, repr_type_ty);
}
None => {}
}
- // Check for unrepresentable discriminant values
- match hint {
- attr::ReprAny | attr::ReprExtern => {
- disr_vals.push(current_disr_val);
- }
- attr::ReprInt(sp, ity) => {
- if !disr_in_range(ccx, ity, current_disr_val) {
- let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082,
- "discriminant value outside specified type");
- span_note!(&mut err, sp,
- "discriminant type specified here");
- err.emit();
- }
- }
- // Error reported elsewhere.
- attr::ReprSimd | attr::ReprPacked => {}
- }
+ disr_vals.push(current_disr_val);
}
}