Skip to content

Commit

Permalink
Move error to typeck::check
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Jan 11, 2015
1 parent e183277 commit add20bb
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 80 deletions.
63 changes: 0 additions & 63 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@
//! a `pub fn new()`.
use self::MethodContext::*;


use fmt_macros::{Parser, Piece, Position};

use metadata::csearch;
use middle::def::*;
use middle::subst::Substs;
Expand Down Expand Up @@ -1924,63 +1921,3 @@ impl LintPass for UnstableFeatures {
}
}
}

/// Checks usage of `#[on_unimplemented]`
#[derive(Copy)]
pub struct BadOnUnimplemented;

declare_lint!(BAD_ON_UNIMPLEMENTED, Deny,
"Checks usage of `#[on_unimplemented]`");

impl LintPass for BadOnUnimplemented {
fn get_lints(&self) -> LintArray {
lint_array!(BAD_ON_UNIMPLEMENTED)
}
fn check_item(&mut self, ctx: &Context, item: &ast::Item) {
match item.node {
ast::ItemTrait(_, ref generics, _, _) => {
if let Some(ref attr) = item.attrs.iter().find(|&: a| {
a.check_name("on_unimplemented")
}) {
if let Some(ref istring) = attr.value_str() {
let mut parser = Parser::new(istring.get());
let types = generics.ty_params.as_slice();
for token in parser {
match token {
Piece::String(_) => (), // Normal string, no need to check it
Piece::NextArgument(a) => match a.position {
// `{Self}` is allowed
Position::ArgumentNamed(s) if s == "Self" => (),
// So is `{A}` if A is a type parameter
Position::ArgumentNamed(s) => match types.iter().find(|t| {
t.ident.as_str() == s
}) {
Some(_) => (),
None => {
ctx.span_lint(BAD_ON_UNIMPLEMENTED, attr.span,
format!("there is no type parameter \
{} on trait {}",
s, item.ident.as_str())
.as_slice());
}
},
// `{:1}` and `{}` are not to be used
Position::ArgumentIs(_) | Position::ArgumentNext => {
ctx.span_lint(BAD_ON_UNIMPLEMENTED, attr.span,
"only named substitution \
parameters are allowed");
}
}
}
}
} else {
ctx.span_lint(BAD_ON_UNIMPLEMENTED, attr.span,
"this attribute must have a value, \
eg `#[on_unimplemented = \"foo\"]`")
}
}
},
_ => () // Not a trait def, move along
}
}
}
1 change: 0 additions & 1 deletion src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ impl LintStore {
UnusedAllocation,
MissingCopyImplementations,
UnstableFeatures,
BadOnUnimplemented,
);

add_builtin_with_new!(sess,
Expand Down
50 changes: 49 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ use self::TupleArgumentsFlag::*;

use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv};
use check::_match::pat_ctxt;
use fmt_macros::{Parser, Piece, Position};
use middle::{const_eval, def};
use middle::infer;
use middle::lang_items::IteratorItem;
Expand Down Expand Up @@ -113,6 +114,7 @@ use std::mem::replace;
use std::rc::Rc;
use std::iter::repeat;
use syntax::{self, abi, attr};
use syntax::attr::AttrMetaMethods;
use syntax::ast::{self, ProvidedMethod, RequiredMethod, TypeTraitItem, DefId};
use syntax::ast_util::{self, local_def, PostExpansionMethod};
use syntax::codemap::{self, Span};
Expand Down Expand Up @@ -726,7 +728,8 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
}

}
ast::ItemTrait(_, _, _, ref trait_methods) => {
ast::ItemTrait(_, ref generics, _, ref trait_methods) => {
check_trait_on_unimplemented(ccx, generics, it);
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
for trait_method in trait_methods.iter() {
match *trait_method {
Expand Down Expand Up @@ -776,6 +779,51 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
}
}

fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
generics: &ast::Generics,
item: &ast::Item) {
if let Some(ref attr) = item.attrs.iter().find(|&: a| {
a.check_name("on_unimplemented")
}) {
if let Some(ref istring) = attr.value_str() {
let mut parser = Parser::new(istring.get());
let types = generics.ty_params.as_slice();
for token in parser {
match token {
Piece::String(_) => (), // Normal string, no need to check it
Piece::NextArgument(a) => match a.position {
// `{Self}` is allowed
Position::ArgumentNamed(s) if s == "Self" => (),
// So is `{A}` if A is a type parameter
Position::ArgumentNamed(s) => match types.iter().find(|t| {
t.ident.as_str() == s
}) {
Some(_) => (),
None => {
ccx.tcx.sess.span_err(attr.span,
format!("there is no type parameter \
{} on trait {}",
s, item.ident.as_str())
.as_slice());
}
},
// `{:1}` and `{}` are not to be used
Position::ArgumentIs(_) | Position::ArgumentNext => {
ccx.tcx.sess.span_err(attr.span,
"only named substitution \
parameters are allowed");
}
}
}
}
} else {
ccx.tcx.sess.span_err(attr.span,
"this attribute must have a value, \
eg `#[on_unimplemented = \"foo\"]`")
}
}
}

/// Type checks a method body.
///
/// # Parameters
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ This API is completely unstable and subject to change.
#[macro_use] extern crate syntax;

extern crate arena;
extern crate fmt_macros;
extern crate rustc;

pub use rustc::lint;
Expand Down
15 changes: 0 additions & 15 deletions src/test/compile-fail/on-unimplemented.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,11 @@ fn collect<A, I: Iterator<Item=A>, B: MyFromIterator<A>>(it: I) -> B {
MyFromIterator::my_from_iter(it)
}

#[on_unimplemented] //~ ERROR the #[on_unimplemented] attribute on trait definition for BadAnnotation1 must have a value, eg `#[on_unimplemented = "foo"]`
trait BadAnnotation1 {}

#[on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
//~^ ERROR the #[on_unimplemented] attribute on trait definition for BadAnnotation2<A, B> refers to non-existent type parameter C
trait BadAnnotation2<A,B> {}

fn trigger1<T: BadAnnotation1>(t: T) {}
fn trigger2<A, B, T: BadAnnotation2<A,B>>(t: T) {}

pub fn main() {
let x = vec!(1u8, 2, 3, 4);
let y: Option<Vec<u8>> = collect(x.iter()); // this should give approximately the same error for x.iter().collect()
//~^ ERROR
//~^^ NOTE a collection of type `core::option::Option<collections::vec::Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
let x: String = foobar(); //~ ERROR
//~^ NOTE test error `collections::string::String` with `u8` `_` `u32`

// The following two have errors in their annotations, so the regular error should be thrown
trigger1(1u8); //~ ERROR the trait `BadAnnotation1` is not implemented for the type `u8`
trigger2::<u8, u8, u8>(1u8); //~ ERROR the trait `BadAnnotation2<u8, u8>` is not implemented

}

0 comments on commit add20bb

Please sign in to comment.