Skip to content

Commit

Permalink
ensure projections are prohibited when type parameters are
Browse files Browse the repository at this point in the history
Technically a [breaking-change], but the broken code is useless,
like `i32<Param=()>`.

Fixes #24682
  • Loading branch information
arielb1 committed Sep 13, 2015
1 parent a41d435 commit 5d44555
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 33 deletions.
1 change: 1 addition & 0 deletions src/librustc/diagnostics.rs
Expand Up @@ -1895,6 +1895,7 @@ register_diagnostics! {
// E0006 // merged with E0005
// E0134,
// E0135,
E0229, // associated type bindings are not allowed here
E0264, // unknown external lang item
E0278, // requirement is not satisfied
E0279, // requirement is not satisfied
Expand Down
40 changes: 22 additions & 18 deletions src/librustc/middle/astconv_util.rs
Expand Up @@ -16,36 +16,40 @@

use middle::def;
use middle::ty::{self, Ty};
use rustc_front::hir as ast;

pub const NO_REGIONS: usize = 1;
pub const NO_TPS: usize = 2;
use syntax::codemap::Span;
use rustc_front::hir as ast;

pub fn check_path_args(tcx: &ty::ctxt, segments: &[ast::PathSegment], flags: usize) {
pub fn prohibit_type_params(tcx: &ty::ctxt, segments: &[ast::PathSegment]) {
for segment in segments {
if (flags & NO_TPS) != 0 {
for typ in segment.parameters.types() {
span_err!(tcx.sess, typ.span, E0109,
"type parameters are not allowed on this type");
break;
}
for typ in segment.parameters.types() {
span_err!(tcx.sess, typ.span, E0109,
"type parameters are not allowed on this type");
break;
}

if (flags & NO_REGIONS) != 0 {
for lifetime in segment.parameters.lifetimes() {
span_err!(tcx.sess, lifetime.span, E0110,
"lifetime parameters are not allowed on this type");
break;
}
for lifetime in segment.parameters.lifetimes() {
span_err!(tcx.sess, lifetime.span, E0110,
"lifetime parameters are not allowed on this type");
break;
}
for binding in segment.parameters.bindings() {
prohibit_projection(tcx, binding.span);
break;
}
}
}

pub fn prohibit_projection(tcx: &ty::ctxt, span: Span)
{
span_err!(tcx.sess, span, E0229,
"associated type bindings are not allowed here");
}

pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
segments: &[ast::PathSegment],
nty: ast::PrimTy)
-> Ty<'tcx> {
check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, segments);
match nty {
ast::TyBool => tcx.types.bool,
ast::TyChar => tcx.types.char,
Expand Down
21 changes: 10 additions & 11 deletions src/librustc_typeck/astconv.rs
Expand Up @@ -48,7 +48,7 @@
//! case but `&a` in the second. Basically, defaults that appear inside
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.

use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_projection};
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def;
Expand Down Expand Up @@ -1210,7 +1210,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,

debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);

check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, slice::ref_slice(item_segment));

// Find the type of the associated item, and the trait where the associated
// item is declared.
Expand Down Expand Up @@ -1312,7 +1312,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
{
let tcx = this.tcx();

check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, slice::ref_slice(item_segment));

let self_ty = if let Some(ty) = opt_self_ty {
ty
Expand Down Expand Up @@ -1401,7 +1401,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
base_segments.last().unwrap(),
&mut projection_bounds);

check_path_args(tcx, base_segments.split_last().unwrap().1, NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, base_segments.split_last().unwrap().1);
trait_ref_to_object_type(this,
rscope,
span,
Expand All @@ -1410,7 +1410,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
&[])
}
def::DefTy(did, _) | def::DefStruct(did) => {
check_path_args(tcx, base_segments.split_last().unwrap().1, NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, base_segments.split_last().unwrap().1);
ast_path_to_ty(this,
rscope,
span,
Expand All @@ -1419,12 +1419,12 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
base_segments.last().unwrap())
}
def::DefTyParam(space, index, _, name) => {
check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, base_segments);
tcx.mk_param(space, index, name)
}
def::DefSelfTy(_, Some((_, self_ty_id))) => {
// Self in impl (we know the concrete type).
check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, base_segments);
if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) {
if let Some(free_substs) = this.get_free_substs() {
ty.subst(tcx, free_substs)
Expand All @@ -1437,11 +1437,11 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
}
def::DefSelfTy(Some(_), None) => {
// Self in trait.
check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, base_segments);
tcx.mk_self_type()
}
def::DefAssociatedTy(trait_did, _) => {
check_path_args(tcx, &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS);
prohibit_type_params(tcx, &base_segments[..base_segments.len()-2]);
qpath_to_ty(this,
rscope,
span,
Expand Down Expand Up @@ -2191,8 +2191,7 @@ fn prohibit_projections<'tcx>(tcx: &ty::ctxt<'tcx>,
bindings: &[ConvertedBinding<'tcx>])
{
for binding in bindings.iter().take(1) {
span_err!(tcx.sess, binding.span, E0229,
"associated type bindings are not allowed here");
prohibit_projection(tcx, binding.span);
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -83,7 +83,7 @@ use self::TupleArgumentsFlag::*;
use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
use check::_match::pat_ctxt;
use fmt_macros::{Parser, Piece, Position};
use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS};
use middle::astconv_util::prohibit_type_params;
use middle::def;
use middle::def_id::{DefId, LOCAL_CRATE};
use middle::infer;
Expand Down Expand Up @@ -4535,8 +4535,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
for (opt_space, segment) in segment_spaces.iter().zip(segments) {
match *opt_space {
None => {
check_path_args(fcx.tcx(), slice::ref_slice(segment),
NO_TPS | NO_REGIONS);
prohibit_type_params(fcx.tcx(), slice::ref_slice(segment));
}

Some(space) => {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_typeck/diagnostics.rs
Expand Up @@ -3294,7 +3294,6 @@ register_diagnostics! {
E0226, // only a single explicit lifetime bound is permitted
E0227, // ambiguous lifetime bound, explicit lifetime bound required
E0228, // explicit lifetime bound required
E0229, // associated type bindings are not allowed here
E0230, // there is no type parameter on trait
E0231, // only named substitution parameters are allowed
// E0233,
Expand Down
31 changes: 31 additions & 0 deletions src/test/compile-fail/issue-24682.rs
@@ -0,0 +1,31 @@
// Copyright 2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait A: Sized {
type N;
fn x() ->
Self<
N= //~ ERROR associated type bindings are not allowed here
Self::N> {
loop {}
}
fn y(&self) ->
std
<N=()> //~ ERROR associated type bindings are not allowed here
::option::Option<()>
{ None }
fn z(&self) ->
u32<N=()> //~ ERROR associated type bindings are not allowed here
{ 42 }

}

fn main() {
}

0 comments on commit 5d44555

Please sign in to comment.