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.
12 use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck};
13 use constrained_type_params::{identify_constrained_type_params, Parameter};
15 use middle::def_id::DefId;
16 use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
18 use middle::ty::{self, Ty};
19 use middle::ty::fold::{TypeFolder};
21 use std::cell::RefCell;
22 use std::collections::HashSet;
25 use syntax::codemap::{Span};
26 use syntax::parse::token::{special_idents};
28 use rustc_front::visit;
29 use rustc_front::visit::Visitor;
32 pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
33 ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
34 code: traits::ObligationCauseCode<'tcx>,
37 impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
38 pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>)
39 -> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
40 CheckTypeWellFormedVisitor {
42 code: traits::ObligationCauseCode::RFC1214(
43 Rc::new(traits::ObligationCauseCode::MiscObligation))
47 fn tcx(&self) -> &ty::ctxt<'tcx> {
51 /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
52 /// well-formed, meaning that they do not require any constraints not declared in the struct
53 /// definition itself. For example, this definition would be illegal:
55 /// struct Ref<'a, T> { x: &'a T }
57 /// because the type did not declare that `T:'a`.
59 /// We do this check as a pre-pass before checking fn bodies because if these constraints are
60 /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
62 fn check_item_well_formed(&mut self, item: &hir::Item) {
64 debug!("check_item_well_formed(it.id={}, it.name={})",
66 ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(item.id)));
69 /// Right now we check that every default trait implementation
70 /// has an implementation of itself. Basically, a case like:
72 /// `impl Trait for T {}`
74 /// has a requirement of `T: Trait` which was required for default
75 /// method implementations. Although this could be improved now that
76 /// there's a better infrastructure in place for this, it's being left
77 /// for a follow-up work.
79 /// Since there's such a requirement, we need to check *just* positive
80 /// implementations, otherwise things like:
82 /// impl !Send for T {}
84 /// won't be allowed unless there's an *explicit* implementation of `Send`
86 hir::ItemImpl(_, hir::ImplPolarity::Positive, _,
87 ref trait_ref, ref self_ty, _) => {
88 self.check_impl(item, self_ty, trait_ref);
90 hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => {
91 // FIXME(#27579) what amount of WF checking do we need for neg impls?
93 let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap();
94 ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id);
95 match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
96 Some(ty::BoundSend) | Some(ty::BoundSync) => {}
98 if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
99 error_192(ccx, item.span);
104 hir::ItemFn(_, _, _, _, _, ref body) => {
105 self.check_item_fn(item, body);
107 hir::ItemStatic(..) => {
108 self.check_item_type(item);
110 hir::ItemConst(..) => {
111 self.check_item_type(item);
113 hir::ItemStruct(ref struct_def, ref ast_generics) => {
114 self.check_type_defn(item, |fcx| {
115 vec![struct_variant(fcx, &**struct_def)]
118 self.check_variances_for_type_defn(item, ast_generics);
120 hir::ItemEnum(ref enum_def, ref ast_generics) => {
121 self.check_type_defn(item, |fcx| {
122 enum_variants(fcx, enum_def)
125 self.check_variances_for_type_defn(item, ast_generics);
127 hir::ItemTrait(_, _, _, ref items) => {
128 self.check_trait(item, items);
134 fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) {
135 let code = self.code.clone();
136 self.with_fcx(item_id, span, |fcx, this| {
137 let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
138 let free_id = fcx.inh.infcx.parameter_environment.free_id;
140 let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id));
142 let mut implied_bounds = match item.container() {
143 ty::TraitContainer(_) => vec![],
144 ty::ImplContainer(def_id) => impl_implied_bounds(fcx, def_id, span)
148 ty::ConstTraitItem(assoc_const) => {
149 let ty = fcx.instantiate_type_scheme(span, free_substs, &assoc_const.ty);
150 fcx.register_wf_obligation(ty, span, code.clone());
152 ty::MethodTraitItem(method) => {
153 reject_shadowing_type_parameters(fcx.tcx(), span, &method.generics);
154 let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
155 let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
156 this.check_fn_or_method(fcx, span, &method_ty, &predicates,
157 free_id, &mut implied_bounds);
159 ty::TypeTraitItem(assoc_type) => {
160 if let Some(ref ty) = assoc_type.ty {
161 let ty = fcx.instantiate_type_scheme(span, free_substs, ty);
162 fcx.register_wf_obligation(ty, span, code.clone());
171 fn with_item_fcx<F>(&mut self, item: &hir::Item, f: F) where
172 F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>,
173 &mut CheckTypeWellFormedVisitor<'ccx,'tcx>) -> Vec<Ty<'tcx>>,
175 self.with_fcx(item.id, item.span, f)
178 fn with_fcx<F>(&mut self, id: ast::NodeId, span: Span, mut f: F) where
179 F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>,
180 &mut CheckTypeWellFormedVisitor<'ccx,'tcx>) -> Vec<Ty<'tcx>>,
183 let param_env = ty::ParameterEnvironment::for_item(ccx.tcx, id);
184 let tables = RefCell::new(ty::Tables::empty());
185 let inh = Inherited::new(ccx.tcx, &tables, param_env);
186 let fcx = blank_fn_ctxt(ccx, &inh, ty::FnDiverging, id);
187 let wf_tys = f(&fcx, self);
188 fcx.select_all_obligations_or_error();
189 regionck::regionck_item(&fcx, id, span, &wf_tys);
192 /// In a type definition, we check that to ensure that the types of the fields are well-formed.
193 fn check_type_defn<F>(&mut self, item: &hir::Item, mut lookup_fields: F) where
194 F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>,
196 self.with_item_fcx(item, |fcx, this| {
197 let variants = lookup_fields(fcx);
199 for variant in &variants {
200 // For DST, all intermediate types must be sized.
201 if let Some((_, fields)) = variant.fields.split_last() {
202 for field in fields {
203 fcx.register_builtin_bound(
206 traits::ObligationCause::new(field.span,
208 traits::FieldSized));
212 // All field types must be well-formed.
213 for field in &variant.fields {
214 fcx.register_wf_obligation(field.ty, field.span, this.code.clone())
218 let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
219 let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
220 let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
221 this.check_where_clauses(fcx, item.span, &predicates);
223 vec![] // no implied bounds in a struct def'n
227 fn check_trait(&mut self,
229 items: &[P<hir::TraitItem>])
231 let trait_def_id = self.tcx().map.local_def_id(item.id);
233 if self.ccx.tcx.trait_has_default_impl(trait_def_id) {
234 if !items.is_empty() {
235 error_380(self.ccx, item.span);
239 self.with_item_fcx(item, |fcx, this| {
240 let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
241 let predicates = fcx.tcx().lookup_predicates(trait_def_id);
242 let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
243 this.check_where_clauses(fcx, item.span, &predicates);
248 fn check_item_fn(&mut self,
252 self.with_item_fcx(item, |fcx, this| {
253 let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
254 let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
255 let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
256 let bare_fn_ty = match item_ty.sty {
257 ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty,
259 this.tcx().sess.span_bug(item.span, "Fn item without bare fn type");
263 let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
264 let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
266 let mut implied_bounds = vec![];
267 this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
268 body.id, &mut implied_bounds);
273 fn check_item_type(&mut self,
276 debug!("check_item_type: {:?}", item);
278 self.with_item_fcx(item, |fcx, this| {
279 let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
280 let item_ty = fcx.instantiate_type_scheme(item.span,
283 .parameter_environment
287 fcx.register_wf_obligation(item_ty, item.span, this.code.clone());
289 vec![] // no implied bounds in a const etc
293 fn check_impl(&mut self,
295 ast_self_ty: &hir::Ty,
296 ast_trait_ref: &Option<hir::TraitRef>)
298 debug!("check_impl: {:?}", item);
300 self.with_item_fcx(item, |fcx, this| {
301 let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
302 let item_def_id = fcx.tcx().map.local_def_id(item.id);
304 match *ast_trait_ref {
305 Some(ref ast_trait_ref) => {
306 let trait_ref = fcx.tcx().impl_trait_ref(item_def_id).unwrap();
308 fcx.instantiate_type_scheme(
309 ast_trait_ref.path.span, free_substs, &trait_ref);
311 ty::wf::trait_obligations(fcx.infcx(),
314 ast_trait_ref.path.span,
316 for obligation in obligations {
317 fcx.register_predicate(obligation);
321 let self_ty = fcx.tcx().node_id_to_type(item.id);
322 let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty);
323 fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone());
327 let predicates = fcx.tcx().lookup_predicates(item_def_id);
328 let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
329 this.check_where_clauses(fcx, item.span, &predicates);
331 impl_implied_bounds(fcx, fcx.tcx().map.local_def_id(item.id), item.span)
335 fn check_where_clauses<'fcx>(&mut self,
336 fcx: &FnCtxt<'fcx,'tcx>,
338 predicates: &ty::InstantiatedPredicates<'tcx>)
341 predicates.predicates
343 .flat_map(|p| ty::wf::predicate_obligations(fcx.infcx(),
349 for obligation in obligations {
350 fcx.register_predicate(obligation);
354 fn check_fn_or_method<'fcx>(&mut self,
355 fcx: &FnCtxt<'fcx,'tcx>,
357 fty: &ty::BareFnTy<'tcx>,
358 predicates: &ty::InstantiatedPredicates<'tcx>,
359 free_id: ast::NodeId,
360 implied_bounds: &mut Vec<Ty<'tcx>>)
362 let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
363 let fty = fcx.instantiate_type_scheme(span, free_substs, fty);
364 let free_id_outlive = fcx.tcx().region_maps.item_extent(free_id);
365 let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig);
367 for &input_ty in &sig.inputs {
368 fcx.register_wf_obligation(input_ty, span, self.code.clone());
370 implied_bounds.extend(sig.inputs);
373 ty::FnConverging(output) => {
374 fcx.register_wf_obligation(output, span, self.code.clone());
376 // FIXME(#25759) return types should not be implied bounds
377 implied_bounds.push(output);
379 ty::FnDiverging => { }
382 self.check_where_clauses(fcx, span, predicates);
385 fn check_variances_for_type_defn(&self,
387 ast_generics: &hir::Generics)
389 let item_def_id = self.tcx().map.local_def_id(item.id);
390 let ty_predicates = self.tcx().lookup_predicates(item_def_id);
391 let variances = self.tcx().item_variances(item_def_id);
393 let mut constrained_parameters: HashSet<_> =
396 .filter(|&(_, _, &variance)| variance != ty::Bivariant)
397 .map(|(space, index, _)| self.param_ty(ast_generics, space, index))
398 .map(|p| Parameter::Type(p))
401 identify_constrained_type_params(self.tcx(),
402 ty_predicates.predicates.as_slice(),
404 &mut constrained_parameters);
406 for (space, index, _) in variances.types.iter_enumerated() {
407 let param_ty = self.param_ty(ast_generics, space, index);
408 if constrained_parameters.contains(&Parameter::Type(param_ty)) {
411 let span = self.ty_param_span(ast_generics, item, space, index);
412 self.report_bivariance(span, param_ty.name);
415 for (space, index, &variance) in variances.regions.iter_enumerated() {
416 if variance != ty::Bivariant {
420 assert_eq!(space, TypeSpace);
421 let span = ast_generics.lifetimes[index].lifetime.span;
422 let name = ast_generics.lifetimes[index].lifetime.name;
423 self.report_bivariance(span, name);
428 ast_generics: &hir::Generics,
433 let name = match space {
434 TypeSpace => ast_generics.ty_params[index].name,
435 SelfSpace => special_idents::type_self.name,
436 FnSpace => self.tcx().sess.bug("Fn space occupied?"),
439 ty::ParamTy { space: space, idx: index as u32, name: name }
442 fn ty_param_span(&self,
443 ast_generics: &hir::Generics,
450 TypeSpace => ast_generics.ty_params[index].span,
451 SelfSpace => item.span,
452 FnSpace => self.tcx().sess.span_bug(item.span, "Fn space occupied?"),
456 fn report_bivariance(&self,
458 param_name: ast::Name)
460 error_392(self.tcx(), span, param_name);
462 let suggested_marker_id = self.tcx().lang_items.phantom_data();
463 match suggested_marker_id {
465 self.tcx().sess.fileline_help(
467 &format!("consider removing `{}` or using a marker such as `{}`",
469 self.tcx().item_path_str(def_id)));
472 // no lang items, no help!
478 fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>,
480 generics: &ty::Generics<'tcx>) {
481 let impl_params = generics.types.get_slice(subst::TypeSpace).iter()
482 .map(|tp| tp.name).collect::<HashSet<_>>();
484 for method_param in generics.types.get_slice(subst::FnSpace) {
485 if impl_params.contains(&method_param.name) {
486 error_194(tcx, span, method_param.name);
491 impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
492 fn visit_item(&mut self, i: &hir::Item) {
493 debug!("visit_item: {:?}", i);
494 self.check_item_well_formed(i);
495 visit::walk_item(self, i);
498 fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
499 debug!("visit_trait_item: {:?}", trait_item);
500 self.check_trait_or_impl_item(trait_item.id, trait_item.span);
501 visit::walk_trait_item(self, trait_item)
504 fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) {
505 debug!("visit_impl_item: {:?}", impl_item);
506 self.check_trait_or_impl_item(impl_item.id, impl_item.span);
507 visit::walk_impl_item(self, impl_item)
511 ///////////////////////////////////////////////////////////////////////////
514 struct AdtVariant<'tcx> {
515 fields: Vec<AdtField<'tcx>>,
518 struct AdtField<'tcx> {
523 fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
524 struct_def: &hir::StructDef)
525 -> AdtVariant<'tcx> {
530 let field_ty = fcx.tcx().node_id_to_type(field.node.id);
531 let field_ty = fcx.instantiate_type_scheme(field.span,
534 .parameter_environment
537 AdtField { ty: field_ty, span: field.span }
540 AdtVariant { fields: fields }
543 fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
544 enum_def: &hir::EnumDef)
545 -> Vec<AdtVariant<'tcx>> {
546 enum_def.variants.iter()
548 match variant.node.kind {
549 hir::TupleVariantKind(ref args) if !args.is_empty() => {
550 let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id);
552 // the regions in the argument types come from the
553 // enum def'n, and hence will all be early bound
554 let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap();
556 fields: args.iter().enumerate().map(|(index, arg)| {
557 let arg_ty = arg_tys[index];
559 fcx.instantiate_type_scheme(variant.span,
562 .parameter_environment
572 hir::TupleVariantKind(_) => {
577 hir::StructVariantKind(ref struct_def) => {
578 struct_variant(fcx, &**struct_def)
585 fn impl_implied_bounds<'fcx,'tcx>(fcx: &FnCtxt<'fcx, 'tcx>,
590 let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
591 match fcx.tcx().impl_trait_ref(impl_def_id) {
592 Some(ref trait_ref) => {
593 // Trait impl: take implied bounds from all types that
594 // appear in the trait reference.
595 let trait_ref = fcx.instantiate_type_scheme(span, free_substs, trait_ref);
596 trait_ref.substs.types.as_slice().to_vec()
600 // Inherent impl: take implied bounds from the self type.
601 let self_ty = fcx.tcx().lookup_item_type(impl_def_id).ty;
602 let self_ty = fcx.instantiate_type_scheme(span, free_substs, &self_ty);
608 pub fn error_192<'ccx,'tcx>(ccx: &'ccx CrateCtxt<'ccx, 'tcx>, span: Span) {
609 span_err!(ccx.tcx.sess, span, E0192,
610 "negative impls are only allowed for traits with \
611 default impls (e.g., `Send` and `Sync`)")
614 pub fn error_380<'ccx,'tcx>(ccx: &'ccx CrateCtxt<'ccx, 'tcx>, span: Span) {
615 span_err!(ccx.tcx.sess, span, E0380,
616 "traits with default impls (`e.g. unsafe impl \
617 Trait for ..`) must have no methods or associated items")
620 pub fn error_392<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, param_name: ast::Name) {
621 span_err!(tcx.sess, span, E0392,
622 "parameter `{}` is never used", param_name);
625 pub fn error_194<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, name: ast::Name) {
626 span_err!(tcx.sess, span, E0194,
627 "type parameter `{}` shadows another type parameter of the same name",