1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 // The job of the coherence phase of typechecking is to ensure that
14 // each trait has at most one implementation for each type. This is
15 // done by the orphan and overlap modules. Then we build up various
16 // mappings. That mapping code resides here.
19 use middle::def_id::{DefId, LOCAL_CRATE};
20 use middle::lang_items::UnsizeTraitLangItem;
21 use middle::subst::{self, Subst};
24 use middle::ty::RegionEscape;
25 use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
26 use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
27 use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
28 use middle::ty::{TyParam, TypeScheme, TyRawPtr};
29 use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple};
30 use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
31 use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn};
32 use middle::ty::TyProjection;
33 use middle::ty::util::CopyImplementationError;
34 use middle::free_region::FreeRegionMap;
36 use middle::infer::{self, InferCtxt, new_infer_ctxt};
37 use std::cell::RefCell;
39 use syntax::codemap::Span;
40 use syntax::parse::token;
41 use util::nodemap::{DefIdMap, FnvHashMap};
42 use rustc::front::map as hir_map;
43 use rustc::front::map::NodeItem;
44 use rustc_front::visit;
45 use rustc_front::hir::{Item, ItemImpl,Crate};
52 // Returns the def ID of the base type, if there is one.
53 fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
64 Some(t.principal_def_id())
68 inference_context.tcx.lang_items.owned_box()
71 TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
72 TyStr(..) | TyArray(..) | TySlice(..) | TyBareFn(..) | TyTuple(..) |
73 TyParam(..) | TyError |
74 TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
78 TyInfer(..) | TyClosure(..) => {
79 // `ty` comes from a user declaration so we should only expect types
80 // that the user can type
81 inference_context.tcx.sess.span_bug(
83 &format!("coherence encountered unexpected type searching for base type: {}",
89 struct CoherenceChecker<'a, 'tcx: 'a> {
90 crate_context: &'a CrateCtxt<'a, 'tcx>,
91 inference_context: InferCtxt<'a, 'tcx>,
92 inherent_impls: RefCell<DefIdMap<Rc<RefCell<Vec<DefId>>>>>,
95 struct CoherenceCheckVisitor<'a, 'tcx: 'a> {
96 cc: &'a CoherenceChecker<'a, 'tcx>
99 impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
100 fn visit_item(&mut self, item: &Item) {
101 if let ItemImpl(..) = item.node {
102 self.cc.check_implementation(item)
105 visit::walk_item(self, item);
109 impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
110 fn check(&self, krate: &Crate) {
111 // Check implementations and traits. This populates the tables
112 // containing the inherent methods and extension methods. It also
113 // builds up the trait inheritance table.
114 let mut visitor = CoherenceCheckVisitor { cc: self };
115 visit::walk_crate(&mut visitor, krate);
117 // Copy over the inherent impls we gathered up during the walk into
119 let mut tcx_inherent_impls =
120 self.crate_context.tcx.inherent_impls.borrow_mut();
121 for (k, v) in self.inherent_impls.borrow().iter() {
122 tcx_inherent_impls.insert((*k).clone(),
123 Rc::new((*v.borrow()).clone()));
126 // Populate the table of destructors. It might seem a bit strange to
127 // do this here, but it's actually the most convenient place, since
128 // the coherence tables contain the trait -> type mappings.
129 self.populate_destructors();
131 // Check to make sure implementations of `Copy` are legal.
132 self.check_implementations_of_copy();
134 // Check to make sure implementations of `CoerceUnsized` are legal
135 // and collect the necessary information from them.
136 self.check_implementations_of_coerce_unsized();
139 fn check_implementation(&self, item: &Item) {
140 let tcx = self.crate_context.tcx;
141 let impl_did = DefId::local(item.id);
142 let self_type = tcx.lookup_item_type(impl_did);
144 // If there are no traits, then this implementation must have a
147 let impl_items = self.create_impl_from_item(item);
149 if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) {
150 debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
154 enforce_trait_manually_implementable(self.crate_context.tcx,
157 self.add_trait_impl(trait_ref, impl_did);
159 // Add the implementation to the mapping from implementation to base
160 // type def ID, if there is a base type for this implementation and
161 // the implementation does not have any associated traits.
162 if let Some(base_type_def_id) = get_base_type_def_id(
163 &self.inference_context, item.span, self_type.ty) {
164 self.add_inherent_impl(base_type_def_id, impl_did);
168 tcx.impl_items.borrow_mut().insert(impl_did, impl_items);
171 // Creates default method IDs and performs type substitutions for an impl
172 // and trait pair. Then, for each provided method in the trait, inserts a
173 // `ProvidedMethodInfo` instance into the `provided_method_sources` map.
174 fn instantiate_default_methods(
177 trait_ref: &ty::TraitRef<'tcx>,
178 all_impl_items: &mut Vec<ImplOrTraitItemId>) {
179 let tcx = self.crate_context.tcx;
180 debug!("instantiate_default_methods(impl_id={:?}, trait_ref={:?})",
183 let impl_type_scheme = tcx.lookup_item_type(impl_id);
185 let prov = tcx.provided_trait_methods(trait_ref.def_id);
186 for trait_method in &prov {
188 let new_id = tcx.sess.next_node_id();
189 let new_did = DefId::local(new_id);
191 debug!("new_did={:?} trait_method={:?}", new_did, trait_method);
193 // Create substitutions for the various trait parameters.
195 Rc::new(subst_receiver_types_in_method_ty(
202 Some(trait_method.def_id)));
204 debug!("new_method_ty={:?}", new_method_ty);
205 all_impl_items.push(MethodTraitItemId(new_did));
207 // construct the polytype for the method based on the
208 // method_ty. it will have all the generics from the
209 // impl, plus its own.
210 let new_polytype = ty::TypeScheme {
211 generics: new_method_ty.generics.clone(),
212 ty: tcx.mk_fn(Some(new_did),
213 tcx.mk_bare_fn(new_method_ty.fty.clone()))
215 debug!("new_polytype={:?}", new_polytype);
217 tcx.register_item_type(new_did, new_polytype);
218 tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone());
219 tcx.impl_or_trait_items
221 .insert(new_did, ty::MethodTraitItem(new_method_ty));
223 // Pair the new synthesized ID up with the
225 self.crate_context.tcx.provided_method_sources.borrow_mut()
226 .insert(new_did, trait_method.def_id);
230 fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
231 match self.inherent_impls.borrow().get(&base_def_id) {
232 Some(implementation_list) => {
233 implementation_list.borrow_mut().push(impl_def_id);
239 self.inherent_impls.borrow_mut().insert(
241 Rc::new(RefCell::new(vec!(impl_def_id))));
244 fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
245 debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
246 impl_trait_ref, impl_def_id);
247 let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
248 trait_def.record_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
251 // Converts an implementation in the AST to a vector of items.
252 fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
254 ItemImpl(_, _, _, _, _, ref impl_items) => {
255 let mut items: Vec<ImplOrTraitItemId> =
256 impl_items.iter().map(|impl_item| {
257 match impl_item.node {
258 hir::ConstImplItem(..) => {
259 ConstTraitItemId(DefId::local(impl_item.id))
261 hir::MethodImplItem(..) => {
262 MethodTraitItemId(DefId::local(impl_item.id))
264 hir::TypeImplItem(_) => {
265 TypeTraitItemId(DefId::local(impl_item.id))
270 let def_id = DefId::local(item.id);
271 if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(def_id) {
272 self.instantiate_default_methods(def_id, &trait_ref, &mut items);
278 self.crate_context.tcx.sess.span_bug(item.span,
279 "can't convert a non-impl \
289 fn populate_destructors(&self) {
290 let tcx = self.crate_context.tcx;
291 let drop_trait = match tcx.lang_items.drop_trait() {
292 Some(id) => id, None => { return }
294 tcx.populate_implementations_for_trait_if_necessary(drop_trait);
295 let drop_trait = tcx.lookup_trait_def(drop_trait);
297 let impl_items = tcx.impl_items.borrow();
299 drop_trait.for_each_impl(tcx, |impl_did| {
300 let items = impl_items.get(&impl_did).unwrap();
301 if items.is_empty() {
302 // We'll error out later. For now, just don't ICE.
305 let method_def_id = items[0];
307 let self_type = tcx.lookup_item_type(impl_did);
308 match self_type.ty.sty {
309 ty::TyEnum(type_def, _) |
310 ty::TyStruct(type_def, _) => {
311 type_def.set_destructor(method_def_id.def_id());
314 // Destructors only work on nominal types.
315 if impl_did.is_local() {
317 match tcx.map.find(impl_did.node) {
318 Some(hir_map::NodeItem(item)) => {
319 span_err!(tcx.sess, item.span, E0120,
320 "the Drop trait may only be implemented on structures");
323 tcx.sess.bug("didn't find impl in ast \
329 tcx.sess.bug("found external impl of Drop trait on \
330 something other than a struct");
337 /// Ensures that implementations of the built-in trait `Copy` are legal.
338 fn check_implementations_of_copy(&self) {
339 let tcx = self.crate_context.tcx;
340 let copy_trait = match tcx.lang_items.copy_trait() {
344 tcx.populate_implementations_for_trait_if_necessary(copy_trait);
345 let copy_trait = tcx.lookup_trait_def(copy_trait);
347 copy_trait.for_each_impl(tcx, |impl_did| {
348 debug!("check_implementations_of_copy: impl_did={:?}",
351 if impl_did.krate != LOCAL_CRATE {
352 debug!("check_implementations_of_copy(): impl not in this \
357 let self_type = tcx.lookup_item_type(impl_did);
358 debug!("check_implementations_of_copy: self_type={:?} (bound)",
361 let span = tcx.map.span(impl_did.node);
362 let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
363 let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs);
364 assert!(!self_type.has_escaping_regions());
366 debug!("check_implementations_of_copy: self_type={:?} (free)",
369 match param_env.can_type_implement_copy(self_type, span) {
371 Err(CopyImplementationError::InfrigingField(name)) => {
372 span_err!(tcx.sess, span, E0204,
373 "the trait `Copy` may not be \
374 implemented for this type; field \
375 `{}` does not implement `Copy`",
378 Err(CopyImplementationError::InfrigingVariant(name)) => {
379 span_err!(tcx.sess, span, E0205,
380 "the trait `Copy` may not be \
381 implemented for this type; variant \
382 `{}` does not implement `Copy`",
385 Err(CopyImplementationError::NotAnAdt) => {
386 span_err!(tcx.sess, span, E0206,
387 "the trait `Copy` may not be implemented \
388 for this type; type is not a structure or \
391 Err(CopyImplementationError::HasDestructor) => {
392 span_err!(tcx.sess, span, E0184,
393 "the trait `Copy` may not be implemented for this type; \
394 the type has a destructor");
400 /// Process implementations of the built-in trait `CoerceUnsized`.
401 fn check_implementations_of_coerce_unsized(&self) {
402 let tcx = self.crate_context.tcx;
403 let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() {
407 let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
410 tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
414 let trait_def = tcx.lookup_trait_def(coerce_unsized_trait);
416 trait_def.for_each_impl(tcx, |impl_did| {
417 debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
420 if impl_did.krate != LOCAL_CRATE {
421 debug!("check_implementations_of_coerce_unsized(): impl not \
426 let source = tcx.lookup_item_type(impl_did).ty;
427 let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
428 let target = *trait_ref.substs.types.get(subst::TypeSpace, 0);
429 debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
432 let span = tcx.map.span(impl_did.node);
433 let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
434 let source = source.subst(tcx, ¶m_env.free_substs);
435 let target = target.subst(tcx, ¶m_env.free_substs);
436 assert!(!source.has_escaping_regions());
438 debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
441 let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env), true);
443 let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,
444 mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
445 if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
446 infcx.report_mismatched_types(span, mk_ptr(mt_b.ty),
447 target, &ty::error::TypeError::Mutability);
449 (mt_a.ty, mt_b.ty, unsize_trait, None)
451 let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
452 (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
454 (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
455 infer::mk_subr(&infcx, infer::RelateObjectBound(span), *r_b, *r_a);
456 check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
459 (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
460 (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
461 check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
464 (&ty::TyStruct(def_a, substs_a), &ty::TyStruct(def_b, substs_b)) => {
466 let source_path = tcx.item_path_str(def_a.did);
467 let target_path = tcx.item_path_str(def_b.did);
468 span_err!(tcx.sess, span, E0377,
469 "the trait `CoerceUnsized` may only be implemented \
470 for a coercion between structures with the same \
471 definition; expected {}, found {}",
472 source_path, target_path);
476 let origin = infer::Misc(span);
477 let fields = &def_a.struct_variant().fields;
478 let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
479 let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
481 if f.unsubst_ty().is_phantom_data() {
482 // Ignore PhantomData fields
484 } else if infcx.sub_types(false, origin, b, a).is_ok() {
485 // Ignore fields that aren't significantly changed
488 // Collect up all fields that were significantly changed
489 // i.e. those that contain T in coerce_unsized T -> U
492 }).collect::<Vec<_>>();
494 if diff_fields.is_empty() {
495 span_err!(tcx.sess, span, E0374,
496 "the trait `CoerceUnsized` may only be implemented \
497 for a coercion between structures with one field \
498 being coerced, none found");
500 } else if diff_fields.len() > 1 {
501 span_err!(tcx.sess, span, E0375,
502 "the trait `CoerceUnsized` may only be implemented \
503 for a coercion between structures with one field \
504 being coerced, but {} fields need coercions: {}",
505 diff_fields.len(), diff_fields.iter().map(|&(i, a, b)| {
506 let name = fields[i].name;
507 format!("{} ({} to {})",
508 if name == token::special_names::unnamed_field {
513 }).collect::<Vec<_>>().join(", "));
517 let (i, a, b) = diff_fields[0];
518 let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
519 (a, b, coerce_unsized_trait, Some(kind))
523 span_err!(tcx.sess, span, E0376,
524 "the trait `CoerceUnsized` may only be implemented \
525 for a coercion between structures");
530 let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
532 // Register an obligation for `A: Trait<B>`.
533 let cause = traits::ObligationCause::misc(span, impl_did.node);
534 let predicate = traits::predicate_for_trait_def(tcx, cause, trait_def_id,
535 0, source, vec![target]);
536 fulfill_cx.register_predicate_obligation(&infcx, predicate);
538 // Check that all transitive obligations are satisfied.
539 if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
540 traits::report_fulfillment_errors(&infcx, &errors);
543 // Finally, resolve all regions.
544 let mut free_regions = FreeRegionMap::new();
545 free_regions.relate_free_regions_from_predicates(tcx, &infcx.parameter_environment
547 infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node);
549 if let Some(kind) = kind {
550 tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
556 fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: DefId) {
557 if tcx.sess.features.borrow().unboxed_closures {
558 // the feature gate allows all of them
561 let did = Some(trait_def_id);
562 let li = &tcx.lang_items;
564 let trait_name = if did == li.fn_trait() {
566 } else if did == li.fn_mut_trait() {
568 } else if did == li.fn_once_trait() {
571 return // everything OK
573 span_err!(tcx.sess, sp, E0183, "manual implementations of `{}` are experimental", trait_name);
574 fileline_help!(tcx.sess, sp,
575 "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
578 fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
580 impl_type_scheme: &ty::TypeScheme<'tcx>,
581 trait_ref: &ty::TraitRef<'tcx>,
583 method: &ty::Method<'tcx>,
584 provided_source: Option<DefId>)
587 let combined_substs = tcx.make_substs_for_receiver_types(trait_ref, method);
589 debug!("subst_receiver_types_in_method_ty: combined_substs={:?}",
592 let method_predicates = method.predicates.subst(tcx, &combined_substs);
593 let mut method_generics = method.generics.subst(tcx, &combined_substs);
595 // replace the type parameters declared on the trait with those
597 for &space in &[subst::TypeSpace, subst::SelfSpace] {
598 method_generics.types.replace(
600 impl_type_scheme.generics.types.get_slice(space).to_vec());
601 method_generics.regions.replace(
603 impl_type_scheme.generics.regions.get_slice(space).to_vec());
606 debug!("subst_receiver_types_in_method_ty: method_generics={:?}",
609 let method_fty = method.fty.subst(tcx, &combined_substs);
611 debug!("subst_receiver_types_in_method_ty: method_ty={:?}",
619 method.explicit_self,
622 ImplContainer(impl_id),
627 pub fn check_coherence(crate_context: &CrateCtxt) {
629 crate_context: crate_context,
630 inference_context: new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None, true),
631 inherent_impls: RefCell::new(FnvHashMap()),
632 }.check(crate_context.tcx.map.krate());
633 unsafety::check(crate_context.tcx);
634 orphan::check(crate_context.tcx);
635 overlap::check(crate_context.tcx);