Skip to content

Commit

Permalink
rollup merge of rust-lang#20465: nikomatsakis/assoc-types-regions-20303
Browse files Browse the repository at this point in the history
Treat associated types the same as type parameters when it comes to region bounding. Fixes rust-lang#20303.

Strictly speaking, this is a [breaking-change] (if you are using
associated types). You are no longer free to wantonly violate the type
system rules by closing associated types into objects without any form
of region bound. Instead you should add region bounds like `T::X :
'a`, just as you would with a normal type parameter.

r? @aturon
  • Loading branch information
alexcrichton committed Jan 6, 2015
2 parents 059566b + 5caf847 commit 88b4c8e
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 109 deletions.
59 changes: 31 additions & 28 deletions src/librustc/middle/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ use super::region_inference::RegionResolutionError;
use super::region_inference::ConcreteFailure;
use super::region_inference::SubSupConflict;
use super::region_inference::SupSupConflict;
use super::region_inference::ParamBoundFailure;
use super::region_inference::GenericBoundFailure;
use super::region_inference::GenericKind;
use super::region_inference::ProcessedErrors;
use super::region_inference::SameRegions;

Expand Down Expand Up @@ -120,11 +121,11 @@ pub trait ErrorReporting<'tcx> {
sub: Region,
sup: Region);

fn report_param_bound_failure(&self,
origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy,
sub: Region,
sups: Vec<Region>);
fn report_generic_bound_failure(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
sub: Region,
sups: Vec<Region>);

fn report_sub_sup_conflict(&self,
var_origin: RegionVariableOrigin,
Expand Down Expand Up @@ -175,8 +176,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
self.report_concrete_failure(origin, sub, sup);
}

ParamBoundFailure(origin, param_ty, sub, sups) => {
self.report_param_bound_failure(origin, param_ty, sub, sups);
GenericBoundFailure(kind, param_ty, sub, sups) => {
self.report_generic_bound_failure(kind, param_ty, sub, sups);
}

SubSupConflict(var_origin,
Expand Down Expand Up @@ -421,63 +422,65 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
found.user_string(self.tcx)))
}

fn report_param_bound_failure(&self,
origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy,
sub: Region,
_sups: Vec<Region>) {

fn report_generic_bound_failure(&self,
origin: SubregionOrigin<'tcx>,
bound_kind: GenericKind<'tcx>,
sub: Region,
_sups: Vec<Region>)
{
// FIXME: it would be better to report the first error message
// with the span of the parameter itself, rather than the span
// where the error was detected. But that span is not readily
// accessible.

let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) =>
format!("the parameter type `{}`", p.user_string(self.tcx)),
GenericKind::Projection(ref p) =>
format!("the associated type `{}`", p.user_string(self.tcx)),
};

match sub {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
format!(
"the parameter type `{}` may not live long enough",
param_ty.user_string(self.tcx))[]);
format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
"consider adding an explicit lifetime bound `{}: {}`...",
param_ty.user_string(self.tcx),
bound_kind.user_string(self.tcx),
sub.user_string(self.tcx))[]);
}

ty::ReStatic => {
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
format!(
"the parameter type `{}` may not live long enough",
param_ty.user_string(self.tcx))[]);
format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
"consider adding an explicit lifetime bound `{}: 'static`...",
param_ty.user_string(self.tcx))[]);
bound_kind.user_string(self.tcx))[]);
}

_ => {
// If not, be less specific.
self.tcx.sess.span_err(
origin.span(),
format!(
"the parameter type `{}` may not live long enough",
param_ty.user_string(self.tcx))[]);
"{} may not live long enough",
labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
"consider adding an explicit lifetime bound to `{}`",
param_ty.user_string(self.tcx))[]);
"consider adding an explicit lifetime bound for `{}`",
bound_kind.user_string(self.tcx))[]);
note_and_explain_region(
self.tcx,
format!("the parameter type `{}` must be valid for ",
param_ty.user_string(self.tcx))[],
format!("{} must be valid for ", labeled_user_string)[],
sub,
"...");
}
Expand Down
28 changes: 15 additions & 13 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub use self::ValuePairs::*;
pub use self::fixup_err::*;
pub use middle::ty::IntVarValue;
pub use self::freshen::TypeFreshener;
pub use self::region_inference::GenericKind;

use middle::subst;
use middle::subst::Substs;
Expand Down Expand Up @@ -382,19 +383,6 @@ pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
cx.region_vars.commit(snapshot);
}

pub fn verify_param_bound<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy,
a: ty::Region,
bs: Vec<ty::Region>) {
debug!("verify_param_bound({}, {} <: {})",
param_ty.repr(cx.tcx),
a.repr(cx.tcx),
bs.repr(cx.tcx));

cx.region_vars.verify_param_bound(origin, param_ty, a, bs);
}

pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool,
origin: TypeOrigin,
Expand Down Expand Up @@ -1070,6 +1058,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
value,
|br, _| self.next_region_var(LateBoundRegion(span, br, lbrct)))
}

/// See `verify_generic_bound` method in `region_inference`
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
a: ty::Region,
bs: Vec<ty::Region>) {
debug!("verify_generic_bound({}, {} <: {})",
kind.repr(self.tcx),
a.repr(self.tcx),
bs.repr(self.tcx));

self.region_vars.verify_generic_bound(origin, kind, a, bs);
}
}

impl<'tcx> TypeTrace<'tcx> {
Expand Down
82 changes: 59 additions & 23 deletions src/librustc/middle/infer/region_inference/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ use super::cres;
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};

use middle::region;
use middle::ty;
use middle::ty::{mod, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
use middle::graph;
use middle::graph::{Direction, NodeIndex};
use util::common::indenter;
use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux::Repr;
use util::ppaux::{Repr, UserString};

use std::cell::{Cell, RefCell};
use std::cmp::Ordering::{self, Less, Greater, Equal};
Expand Down Expand Up @@ -61,12 +61,18 @@ pub enum Verify<'tcx> {
// `b` are inference variables.
VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region),

// VerifyParamBound(T, _, R, RS): The parameter type `T` must
// outlive the region `R`. `T` is known to outlive `RS`. Therefore
// verify that `R <= RS[i]` for some `i`. Inference variables may
// be involved (but this verification step doesn't influence
// inference).
VerifyParamBound(ty::ParamTy, SubregionOrigin<'tcx>, Region, Vec<Region>),
// VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
// associated type) must outlive the region `R`. `T` is known to
// outlive `RS`. Therefore verify that `R <= RS[i]` for some
// `i`. Inference variables may be involved (but this verification
// step doesn't influence inference).
VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec<Region>),
}

#[deriving(Clone, Show, PartialEq, Eq)]
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),
}

#[derive(Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -98,12 +104,12 @@ pub enum RegionResolutionError<'tcx> {
/// `o` requires that `a <= b`, but this does not hold
ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),

/// `ParamBoundFailure(p, s, a, bs)
/// `GenericBoundFailure(p, s, a, bs)
///
/// The parameter type `p` must be known to outlive the lifetime
/// The parameter/assocated-type `p` must be known to outlive the lifetime
/// `a`, but it is only known to outlive `bs` (and none of the
/// regions in `bs` outlive `a`).
ParamBoundFailure(SubregionOrigin<'tcx>, ty::ParamTy, Region, Vec<Region>),
GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region, Vec<Region>),

/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
///
Expand Down Expand Up @@ -489,12 +495,13 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
}
}

pub fn verify_param_bound(&self,
origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy,
sub: Region,
sups: Vec<Region>) {
self.add_verify(VerifyParamBound(param_ty, origin, sub, sups));
/// See `Verify::VerifyGenericBound`
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
sub: Region,
sups: Vec<Region>) {
self.add_verify(VerifyGenericBound(kind, origin, sub, sups));
}

pub fn lub_regions(&self,
Expand Down Expand Up @@ -660,7 +667,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
&mut result_set, r,
a, b);
}
VerifyParamBound(_, _, a, ref bs) => {
VerifyGenericBound(_, _, a, ref bs) => {
for &b in bs.iter() {
consider_adding_bidirectional_edges(
&mut result_set, r,
Expand Down Expand Up @@ -1211,7 +1218,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
errors.push(ConcreteFailure((*origin).clone(), sub, sup));
}

VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => {
VerifyGenericBound(ref kind, ref origin, sub, ref sups) => {
let sub = normalize(values, sub);
if sups.iter()
.map(|&sup| normalize(values, sup))
Expand All @@ -1223,8 +1230,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
let sups = sups.iter().map(|&sup| normalize(values, sup))
.collect();
errors.push(
ParamBoundFailure(
(*origin).clone(), *param_ty, sub, sups));
GenericBoundFailure(
(*origin).clone(), kind.clone(), sub, sups));
}
}
}
Expand Down Expand Up @@ -1584,8 +1591,8 @@ impl<'tcx> Repr<'tcx> for Verify<'tcx> {
VerifyRegSubReg(_, ref a, ref b) => {
format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
}
VerifyParamBound(_, ref p, ref a, ref bs) => {
format!("VerifyParamBound({}, {}, {})",
VerifyGenericBound(_, ref p, ref a, ref bs) => {
format!("VerifyGenericBound({}, {}, {})",
p.repr(tcx), a.repr(tcx), bs.repr(tcx))
}
}
Expand Down Expand Up @@ -1624,3 +1631,32 @@ impl<'tcx> Repr<'tcx> for RegionAndOrigin<'tcx> {
self.origin.repr(tcx))
}
}

impl<'tcx> Repr<'tcx> for GenericKind<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
GenericKind::Param(ref p) => p.repr(tcx),
GenericKind::Projection(ref p) => p.repr(tcx),
}
}
}

impl<'tcx> UserString<'tcx> for GenericKind<'tcx> {
fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
GenericKind::Param(ref p) => p.user_string(tcx),
GenericKind::Projection(ref p) => p.user_string(tcx),
}
}
}

impl<'tcx> GenericKind<'tcx> {
pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
match *self {
GenericKind::Param(ref p) =>
p.to_ty(tcx),
GenericKind::Projection(ref p) =>
ty::mk_projection(tcx, p.trait_ref.clone(), p.item_name),
}
}
}
11 changes: 6 additions & 5 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,11 +643,12 @@ fn confirm_candidate<'cx,'tcx>(
match impl_ty {
Some(ty) => (ty, impl_vtable.nested.to_vec()),
None => {
selcx.tcx().sess.span_bug(
obligation.cause.span,
format!("impl `{}` did not contain projection for `{}`",
impl_vtable.repr(selcx.tcx()),
obligation.repr(selcx.tcx())).as_slice());
// This means that the impl is missing a
// definition for the associated type. This error
// ought to be reported by the type checker method
// `check_impl_items_against_trait`, so here we
// just return ty_err.
(selcx.tcx().types.err, vec!())
}
}
}
Expand Down
Loading

0 comments on commit 88b4c8e

Please sign in to comment.