From e4b913f60f109e0646f532a9b74e9dbd8ac06b1b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 24 Oct 2014 11:25:35 +1300 Subject: s/vtable2/vtable --- src/librustc/middle/typeck/check/method.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 14 +- src/librustc/middle/typeck/check/regionck.rs | 4 +- src/librustc/middle/typeck/check/vtable.rs | 415 +++++++++++++++++++++++++++ src/librustc/middle/typeck/check/vtable2.rs | 415 --------------------------- src/librustc/middle/typeck/check/wf.rs | 4 +- 6 files changed, 427 insertions(+), 427 deletions(-) create mode 100644 src/librustc/middle/typeck/check/vtable.rs delete mode 100644 src/librustc/middle/typeck/check/vtable2.rs (limited to 'src') diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 4560c519464..b768bb8f2d6 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -88,7 +88,7 @@ use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::check::{FnCtxt, NoPreference, PreferMutLvalue}; use middle::typeck::check::{impl_self_ty}; -use middle::typeck::check::vtable2::select_fcx_obligations_where_possible; +use middle::typeck::check::vtable::select_fcx_obligations_where_possible; use middle::typeck::check; use middle::typeck::infer; use middle::typeck::{MethodCall, MethodCallee}; diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 5f7b31e573a..596e30f00cd 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -139,7 +139,7 @@ use syntax::visit::Visitor; use syntax; pub mod _match; -pub mod vtable2; // New trait code +pub mod vtable; pub mod writeback; pub mod regionmanip; pub mod regionck; @@ -409,7 +409,7 @@ fn check_bare_fn(ccx: &CrateCtxt, let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig, decl, id, body, &inh); - vtable2::select_all_fcx_obligations_or_error(&fcx); + vtable::select_all_fcx_obligations_or_error(&fcx); regionck::regionck_fn(&fcx, id, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); } @@ -1377,7 +1377,7 @@ fn check_cast(fcx: &FnCtxt, if ty::type_is_trait(t_1) { // This will be looked up later on. - vtable2::check_object_cast(fcx, cast_expr, e, t_1); + vtable::check_object_cast(fcx, cast_expr, e, t_1); fcx.write_ty(id, t_1); return } @@ -1682,7 +1682,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::UnsizeVtable(ref ty_trait, self_ty) => { // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` implements `Foo`: - vtable2::register_object_cast_obligations(self, + vtable::register_object_cast_obligations(self, span, ty_trait, self_ty); @@ -2565,7 +2565,7 @@ fn check_argument_types<'a>(fcx: &FnCtxt, // an "opportunistic" vtable resolution of any trait // bounds on the call. if check_blocks { - vtable2::select_fcx_obligations_where_possible(fcx); + vtable::select_fcx_obligations_where_possible(fcx); } // For variadic functions, we don't have a declared type for all of @@ -4037,7 +4037,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ast::ExprForLoop(ref pat, ref head, ref block, _) => { check_expr(fcx, &**head); let typ = lookup_method_for_for_loop(fcx, &**head, expr.id); - vtable2::select_fcx_obligations_where_possible(fcx); + vtable::select_fcx_obligations_where_possible(fcx); let pcx = pat_ctxt { fcx: fcx, @@ -4744,7 +4744,7 @@ pub fn check_const_with_ty(fcx: &FnCtxt, check_expr_with_hint(fcx, e, declty); demand::coerce(fcx, e.span, declty, e); - vtable2::select_all_fcx_obligations_or_error(fcx); + vtable::select_all_fcx_obligations_or_error(fcx); regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 76074120c0e..7cca4f241d1 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -126,7 +126,7 @@ use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::check::FnCtxt; use middle::typeck::check::regionmanip; -use middle::typeck::check::vtable2; +use middle::typeck::check::vtable; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; use middle::typeck::infer; @@ -172,7 +172,7 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) { // Region checking a fn can introduce new trait obligations, // particularly around closure bounds. - vtable2::select_all_fcx_obligations_or_error(fcx); + vtable::select_all_fcx_obligations_or_error(fcx); fcx.infcx().resolve_regions_and_report_errors(); } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs new file mode 100644 index 00000000000..d557a2b713b --- /dev/null +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -0,0 +1,415 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::subst::{SelfSpace}; +use middle::traits; +use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; +use middle::traits::{Obligation, obligation_for_builtin_bound}; +use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity}; +use middle::traits::{ObligationCause}; +use middle::ty; +use middle::typeck::check::{FnCtxt, + structurally_resolved_type}; +use middle::typeck::infer; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::Span; +use util::ppaux::UserString; +use util::ppaux::Repr; + +pub fn check_object_cast(fcx: &FnCtxt, + cast_expr: &ast::Expr, + source_expr: &ast::Expr, + target_object_ty: ty::t) +{ + debug!("check_object_cast(cast_expr={}, target_object_ty={})", + cast_expr.repr(fcx.tcx()), + target_object_ty.repr(fcx.tcx())); + + // Look up vtables for the type we're casting to, + // passing in the source and target type. The source + // must be a pointer type suitable to the object sigil, + // e.g.: `&x as &Trait` or `box x as Box` + let source_ty = fcx.expr_ty(source_expr); + let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty); + debug!("source_ty={}", source_ty.repr(fcx.tcx())); + match (&ty::get(source_ty).sty, &ty::get(target_object_ty).sty) { + (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => { + let object_trait = object_trait(&object_trait_ty); + + // Ensure that if ~T is cast to ~Trait, then T : Trait + push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); + } + + (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, + mutbl: referent_mutbl }), + &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty, + mutbl: target_mutbl })) => + { + let object_trait = object_trait(&object_trait_ty); + if !mutability_allowed(referent_mutbl, target_mutbl) { + fcx.tcx().sess.span_err(source_expr.span, + "types differ in mutability"); + } else { + // Ensure that if &'a T is cast to &'b Trait, then T : Trait + push_cast_obligation(fcx, cast_expr, + object_trait, + referent_ty); + + // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a + infer::mk_subr(fcx.infcx(), + infer::RelateObjectBound(source_expr.span), + target_region, + referent_region); + } + } + + (_, &ty::ty_uniq(..)) => { + fcx.ccx.tcx.sess.span_err( + source_expr.span, + format!("can only cast an boxed pointer \ + to a boxed object, not a {}", + ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); + } + + (_, &ty::ty_rptr(..)) => { + fcx.ccx.tcx.sess.span_err( + source_expr.span, + format!("can only cast a &-pointer \ + to an &-object, not a {}", + ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); + } + + _ => { + fcx.tcx().sess.span_bug( + source_expr.span, + "expected object type"); + } + } + + // Because we currently give unsound lifetimes to the "t_box", I + // could have written &'static ty::TyTrait here, but it seems + // gratuitously unsafe. + fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait { + match ty::get(*t).sty { + ty::ty_trait(ref ty_trait) => &**ty_trait, + _ => fail!("expected ty_trait") + } + } + + fn mutability_allowed(a_mutbl: ast::Mutability, + b_mutbl: ast::Mutability) + -> bool { + a_mutbl == b_mutbl || + (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable) + } + + fn push_cast_obligation(fcx: &FnCtxt, + cast_expr: &ast::Expr, + object_trait: &ty::TyTrait, + referent_ty: ty::t) { + let object_trait_ref = + register_object_cast_obligations(fcx, + cast_expr.span, + object_trait, + referent_ty); + + // Finally record the object_trait_ref for use during trans + // (it would prob be better not to do this, but it's just kind + // of a pain to have to reconstruct it). + fcx.write_object_cast(cast_expr.id, object_trait_ref); + } +} + +pub fn register_object_cast_obligations(fcx: &FnCtxt, + span: Span, + object_trait: &ty::TyTrait, + referent_ty: ty::t) + -> Rc +{ + // This is just for better error reporting. Kinda goofy. The object type stuff + // needs some refactoring so there is a more convenient type to pass around. + let object_trait_ty = + ty::mk_trait(fcx.tcx(), + object_trait.def_id, + object_trait.substs.clone(), + object_trait.bounds); + + debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", + referent_ty.repr(fcx.tcx()), + object_trait_ty.repr(fcx.tcx())); + + // Take the type parameters from the object type, but set + // the Self type (which is unknown, for the object type) + // to be the type we are casting from. + let mut object_substs = object_trait.substs.clone(); + assert!(object_substs.self_ty().is_none()); + object_substs.types.push(SelfSpace, referent_ty); + + // Create the obligation for casting from T to Trait. + let object_trait_ref = + Rc::new(ty::TraitRef { def_id: object_trait.def_id, + substs: object_substs }); + let object_obligation = + Obligation::new( + ObligationCause::new(span, + traits::ObjectCastObligation(object_trait_ty)), + object_trait_ref.clone()); + fcx.register_obligation(object_obligation); + + // Create additional obligations for all the various builtin + // bounds attached to the object cast. (In other words, if the + // object type is Foo+Send, this would create an obligation + // for the Send check.) + for builtin_bound in object_trait.bounds.builtin_bounds.iter() { + let obligation = obligation_for_builtin_bound( + fcx.tcx(), + ObligationCause::new(span, + traits::ObjectCastObligation(object_trait_ty)), + referent_ty, + builtin_bound); + match obligation { + Ok(obligation) => fcx.register_obligation(obligation), + _ => {} + } + } + + object_trait_ref +} + +pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { + debug!("select_all_fcx_obligations_or_error"); + + let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut(); + let r = fulfillment_cx.select_all_or_error(fcx.infcx(), + &fcx.inh.param_env, + fcx); + match r { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation) + -> (ty::TraitRef, ty::t) +{ + let trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &*obligation.trait_ref); + let self_ty = + trait_ref.substs.self_ty().unwrap(); + (trait_ref, self_ty) +} + +pub fn report_fulfillment_errors(fcx: &FnCtxt, + errors: &Vec) { + for error in errors.iter() { + report_fulfillment_error(fcx, error); + } +} + +pub fn report_fulfillment_error(fcx: &FnCtxt, + error: &FulfillmentError) { + match error.code { + CodeSelectionError(ref e) => { + report_selection_error(fcx, &error.obligation, e); + } + CodeAmbiguity => { + maybe_report_ambiguity(fcx, &error.obligation); + } + } +} + +pub fn report_selection_error(fcx: &FnCtxt, + obligation: &Obligation, + error: &SelectionError) +{ + match *error { + Overflow => { + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "overflow evaluating the trait `{}` for the type `{}`", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } + Unimplemented => { + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if !ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "the trait `{}` is not implemented for the type `{}`", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } + } + OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => { + let expected_trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &**expected_trait_ref); + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if !ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + self_ty.user_string(fcx.tcx()), + expected_trait_ref.user_string(fcx.tcx()), + trait_ref.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), e)).as_slice()); + note_obligation_cause(fcx, obligation); + } + } + } +} + +pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", + trait_ref.repr(fcx.tcx()), + self_ty.repr(fcx.tcx()), + obligation.repr(fcx.tcx())); + let all_types = &trait_ref.substs.types; + if all_types.iter().any(|&t| ty::type_is_error(t)) { + } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { + // This is kind of a hack: it frequently happens that some earlier + // error prevents types from being fully inferred, and then we get + // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we + // could just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might be an + // inference variable created, registered as an obligation, and + // then never forced by writeback, and hence by skipping here we'd + // be ignoring the fact that we don't KNOW the type works + // out. Though even that would probably be harmless, given that + // we're only talking about builtin traits, which are known to be + // inhabited. But in any case I just threw in this check for + // has_errors() to be sure that compilation isn't happening + // anyway. In that case, why inundate the user. + if !fcx.tcx().sess.has_errors() { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "unable to infer enough type information to \ + locate the impl of the trait `{}` for \ + the type `{}`; type annotations required", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } + } else if !fcx.tcx().sess.has_errors() { + // Ambiguity. Coherence should have reported an error. + fcx.tcx().sess.span_bug( + obligation.cause.span, + format!( + "coherence failed to report ambiguity: \ + cannot locate the impl of the trait `{}` for \ + the type `{}`", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + } +} + +pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) { + /*! Select as many obligations as we can at present. */ + + match + fcx.inh.fulfillment_cx + .borrow_mut() + .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +fn note_obligation_cause(fcx: &FnCtxt, + obligation: &Obligation) { + let tcx = fcx.tcx(); + let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id); + match obligation.cause.code { + traits::MiscObligation => { } + traits::ItemObligation(item_def_id) => { + let item_name = ty::item_path_str(tcx, item_def_id); + tcx.sess.span_note( + obligation.cause.span, + format!( + "the trait `{}` must be implemented because it is required by `{}`", + trait_name, + item_name).as_slice()); + } + traits::ObjectCastObligation(object_ty) => { + tcx.sess.span_note( + obligation.cause.span, + format!( + "the trait `{}` must be implemented for the cast \ + to the object type `{}`", + trait_name, + fcx.infcx().ty_to_string(object_ty)).as_slice()); + } + traits::RepeatVec => { + tcx.sess.span_note( + obligation.cause.span, + "the `Copy` trait is required because the \ + repeated element will be copied"); + } + traits::VariableType(_) => { + tcx.sess.span_note( + obligation.cause.span, + "all local variables must have a statically known size"); + } + traits::ReturnType => { + tcx.sess.span_note( + obligation.cause.span, + "the return type of a function must have a \ + statically known size"); + } + traits::AssignmentLhsSized => { + tcx.sess.span_note( + obligation.cause.span, + "the left-hand-side of an assignment must have a statically known size"); + } + traits::StructInitializerSized => { + tcx.sess.span_note( + obligation.cause.span, + "structs must have a statically known size to be initialized"); + } + traits::DropTrait => { + span_note!(tcx.sess, obligation.cause.span, + "cannot implement a destructor on a \ + structure or enumeration that does not satisfy Send"); + span_note!(tcx.sess, obligation.cause.span, + "use \"#[unsafe_destructor]\" on the implementation \ + to force the compiler to allow this"); + } + traits::ClosureCapture(var_id, closure_span) => { + let name = ty::local_var_name_str(tcx, var_id); + span_note!(tcx.sess, closure_span, + "the closure that captures `{}` requires that all captured variables \" + implement the trait `{}`", + name, + trait_name); + } + traits::FieldSized => { + span_note!(tcx.sess, obligation.cause.span, + "only the last field of a struct or enum variant \ + may have a dynamically sized type") + } + } +} diff --git a/src/librustc/middle/typeck/check/vtable2.rs b/src/librustc/middle/typeck/check/vtable2.rs deleted file mode 100644 index d557a2b713b..00000000000 --- a/src/librustc/middle/typeck/check/vtable2.rs +++ /dev/null @@ -1,415 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use middle::subst::{SelfSpace}; -use middle::traits; -use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; -use middle::traits::{Obligation, obligation_for_builtin_bound}; -use middle::traits::{FulfillmentError, CodeSelectionError, CodeAmbiguity}; -use middle::traits::{ObligationCause}; -use middle::ty; -use middle::typeck::check::{FnCtxt, - structurally_resolved_type}; -use middle::typeck::infer; -use std::rc::Rc; -use syntax::ast; -use syntax::codemap::Span; -use util::ppaux::UserString; -use util::ppaux::Repr; - -pub fn check_object_cast(fcx: &FnCtxt, - cast_expr: &ast::Expr, - source_expr: &ast::Expr, - target_object_ty: ty::t) -{ - debug!("check_object_cast(cast_expr={}, target_object_ty={})", - cast_expr.repr(fcx.tcx()), - target_object_ty.repr(fcx.tcx())); - - // Look up vtables for the type we're casting to, - // passing in the source and target type. The source - // must be a pointer type suitable to the object sigil, - // e.g.: `&x as &Trait` or `box x as Box` - let source_ty = fcx.expr_ty(source_expr); - let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty); - debug!("source_ty={}", source_ty.repr(fcx.tcx())); - match (&ty::get(source_ty).sty, &ty::get(target_object_ty).sty) { - (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => { - let object_trait = object_trait(&object_trait_ty); - - // Ensure that if ~T is cast to ~Trait, then T : Trait - push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); - } - - (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, - mutbl: referent_mutbl }), - &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty, - mutbl: target_mutbl })) => - { - let object_trait = object_trait(&object_trait_ty); - if !mutability_allowed(referent_mutbl, target_mutbl) { - fcx.tcx().sess.span_err(source_expr.span, - "types differ in mutability"); - } else { - // Ensure that if &'a T is cast to &'b Trait, then T : Trait - push_cast_obligation(fcx, cast_expr, - object_trait, - referent_ty); - - // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a - infer::mk_subr(fcx.infcx(), - infer::RelateObjectBound(source_expr.span), - target_region, - referent_region); - } - } - - (_, &ty::ty_uniq(..)) => { - fcx.ccx.tcx.sess.span_err( - source_expr.span, - format!("can only cast an boxed pointer \ - to a boxed object, not a {}", - ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); - } - - (_, &ty::ty_rptr(..)) => { - fcx.ccx.tcx.sess.span_err( - source_expr.span, - format!("can only cast a &-pointer \ - to an &-object, not a {}", - ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); - } - - _ => { - fcx.tcx().sess.span_bug( - source_expr.span, - "expected object type"); - } - } - - // Because we currently give unsound lifetimes to the "t_box", I - // could have written &'static ty::TyTrait here, but it seems - // gratuitously unsafe. - fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait { - match ty::get(*t).sty { - ty::ty_trait(ref ty_trait) => &**ty_trait, - _ => fail!("expected ty_trait") - } - } - - fn mutability_allowed(a_mutbl: ast::Mutability, - b_mutbl: ast::Mutability) - -> bool { - a_mutbl == b_mutbl || - (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable) - } - - fn push_cast_obligation(fcx: &FnCtxt, - cast_expr: &ast::Expr, - object_trait: &ty::TyTrait, - referent_ty: ty::t) { - let object_trait_ref = - register_object_cast_obligations(fcx, - cast_expr.span, - object_trait, - referent_ty); - - // Finally record the object_trait_ref for use during trans - // (it would prob be better not to do this, but it's just kind - // of a pain to have to reconstruct it). - fcx.write_object_cast(cast_expr.id, object_trait_ref); - } -} - -pub fn register_object_cast_obligations(fcx: &FnCtxt, - span: Span, - object_trait: &ty::TyTrait, - referent_ty: ty::t) - -> Rc -{ - // This is just for better error reporting. Kinda goofy. The object type stuff - // needs some refactoring so there is a more convenient type to pass around. - let object_trait_ty = - ty::mk_trait(fcx.tcx(), - object_trait.def_id, - object_trait.substs.clone(), - object_trait.bounds); - - debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", - referent_ty.repr(fcx.tcx()), - object_trait_ty.repr(fcx.tcx())); - - // Take the type parameters from the object type, but set - // the Self type (which is unknown, for the object type) - // to be the type we are casting from. - let mut object_substs = object_trait.substs.clone(); - assert!(object_substs.self_ty().is_none()); - object_substs.types.push(SelfSpace, referent_ty); - - // Create the obligation for casting from T to Trait. - let object_trait_ref = - Rc::new(ty::TraitRef { def_id: object_trait.def_id, - substs: object_substs }); - let object_obligation = - Obligation::new( - ObligationCause::new(span, - traits::ObjectCastObligation(object_trait_ty)), - object_trait_ref.clone()); - fcx.register_obligation(object_obligation); - - // Create additional obligations for all the various builtin - // bounds attached to the object cast. (In other words, if the - // object type is Foo+Send, this would create an obligation - // for the Send check.) - for builtin_bound in object_trait.bounds.builtin_bounds.iter() { - let obligation = obligation_for_builtin_bound( - fcx.tcx(), - ObligationCause::new(span, - traits::ObjectCastObligation(object_trait_ty)), - referent_ty, - builtin_bound); - match obligation { - Ok(obligation) => fcx.register_obligation(obligation), - _ => {} - } - } - - object_trait_ref -} - -pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { - debug!("select_all_fcx_obligations_or_error"); - - let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut(); - let r = fulfillment_cx.select_all_or_error(fcx.infcx(), - &fcx.inh.param_env, - fcx); - match r { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx, &errors); } - } -} - -fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation) - -> (ty::TraitRef, ty::t) -{ - let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &*obligation.trait_ref); - let self_ty = - trait_ref.substs.self_ty().unwrap(); - (trait_ref, self_ty) -} - -pub fn report_fulfillment_errors(fcx: &FnCtxt, - errors: &Vec) { - for error in errors.iter() { - report_fulfillment_error(fcx, error); - } -} - -pub fn report_fulfillment_error(fcx: &FnCtxt, - error: &FulfillmentError) { - match error.code { - CodeSelectionError(ref e) => { - report_selection_error(fcx, &error.obligation, e); - } - CodeAmbiguity => { - maybe_report_ambiguity(fcx, &error.obligation); - } - } -} - -pub fn report_selection_error(fcx: &FnCtxt, - obligation: &Obligation, - error: &SelectionError) -{ - match *error { - Overflow => { - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow evaluating the trait `{}` for the type `{}`", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx())).as_slice()); - note_obligation_cause(fcx, obligation); - } - Unimplemented => { - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); - if !ty::type_is_error(self_ty) { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "the trait `{}` is not implemented for the type `{}`", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx())).as_slice()); - note_obligation_cause(fcx, obligation); - } - } - OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => { - let expected_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &**expected_trait_ref); - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); - if !ty::type_is_error(self_ty) { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - self_ty.user_string(fcx.tcx()), - expected_trait_ref.user_string(fcx.tcx()), - trait_ref.user_string(fcx.tcx()), - ty::type_err_to_str(fcx.tcx(), e)).as_slice()); - note_obligation_cause(fcx, obligation); - } - } - } -} - -pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); - debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", - trait_ref.repr(fcx.tcx()), - self_ty.repr(fcx.tcx()), - obligation.repr(fcx.tcx())); - let all_types = &trait_ref.substs.types; - if all_types.iter().any(|&t| ty::type_is_error(t)) { - } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like " doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. But in any case I just threw in this check for - // has_errors() to be sure that compilation isn't happening - // anyway. In that case, why inundate the user. - if !fcx.tcx().sess.has_errors() { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "unable to infer enough type information to \ - locate the impl of the trait `{}` for \ - the type `{}`; type annotations required", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx())).as_slice()); - note_obligation_cause(fcx, obligation); - } - } else if !fcx.tcx().sess.has_errors() { - // Ambiguity. Coherence should have reported an error. - fcx.tcx().sess.span_bug( - obligation.cause.span, - format!( - "coherence failed to report ambiguity: \ - cannot locate the impl of the trait `{}` for \ - the type `{}`", - trait_ref.user_string(fcx.tcx()), - self_ty.user_string(fcx.tcx())).as_slice()); - } -} - -pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) { - /*! Select as many obligations as we can at present. */ - - match - fcx.inh.fulfillment_cx - .borrow_mut() - .select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx) - { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx, &errors); } - } -} - -fn note_obligation_cause(fcx: &FnCtxt, - obligation: &Obligation) { - let tcx = fcx.tcx(); - let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id); - match obligation.cause.code { - traits::MiscObligation => { } - traits::ItemObligation(item_def_id) => { - let item_name = ty::item_path_str(tcx, item_def_id); - tcx.sess.span_note( - obligation.cause.span, - format!( - "the trait `{}` must be implemented because it is required by `{}`", - trait_name, - item_name).as_slice()); - } - traits::ObjectCastObligation(object_ty) => { - tcx.sess.span_note( - obligation.cause.span, - format!( - "the trait `{}` must be implemented for the cast \ - to the object type `{}`", - trait_name, - fcx.infcx().ty_to_string(object_ty)).as_slice()); - } - traits::RepeatVec => { - tcx.sess.span_note( - obligation.cause.span, - "the `Copy` trait is required because the \ - repeated element will be copied"); - } - traits::VariableType(_) => { - tcx.sess.span_note( - obligation.cause.span, - "all local variables must have a statically known size"); - } - traits::ReturnType => { - tcx.sess.span_note( - obligation.cause.span, - "the return type of a function must have a \ - statically known size"); - } - traits::AssignmentLhsSized => { - tcx.sess.span_note( - obligation.cause.span, - "the left-hand-side of an assignment must have a statically known size"); - } - traits::StructInitializerSized => { - tcx.sess.span_note( - obligation.cause.span, - "structs must have a statically known size to be initialized"); - } - traits::DropTrait => { - span_note!(tcx.sess, obligation.cause.span, - "cannot implement a destructor on a \ - structure or enumeration that does not satisfy Send"); - span_note!(tcx.sess, obligation.cause.span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); - } - traits::ClosureCapture(var_id, closure_span) => { - let name = ty::local_var_name_str(tcx, var_id); - span_note!(tcx.sess, closure_span, - "the closure that captures `{}` requires that all captured variables \" - implement the trait `{}`", - name, - trait_name); - } - traits::FieldSized => { - span_note!(tcx.sess, obligation.cause.span, - "only the last field of a struct or enum variant \ - may have a dynamically sized type") - } - } -} diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index dc79fd4aa32..3c594fbf2d3 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -14,7 +14,7 @@ use middle::traits; use middle::ty; use middle::ty_fold::{TypeFolder, TypeFoldable}; use middle::typeck::astconv::AstConv; -use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck}; +use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; use middle::typeck::check::regionmanip::replace_late_bound_regions; use middle::typeck::CrateCtxt; use util::ppaux::Repr; @@ -100,7 +100,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let inh = Inherited::new(ccx.tcx, param_env); let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id); f(self, &fcx); - vtable2::select_all_fcx_obligations_or_error(&fcx); + vtable::select_all_fcx_obligations_or_error(&fcx); regionck::regionck_item(&fcx, item); } -- cgit 1.4.1-3-g733a5