Explicitly requesting an instantiation
diff --git a/syntax/check.rs b/syntax/check.rs
index f256948..ff23ec9 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -3,8 +3,8 @@
use crate::syntax::report::Errors;
use crate::syntax::types::TrivialReason;
use crate::syntax::{
- error, ident, Api, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Slice, Struct, Ty1, Type,
- Types,
+ error, ident, Api, Enum, ExternFn, ExternType, Impl, Lang, Receiver, Ref, Slice, Struct, Ty1,
+ Type, Types,
};
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
use quote::{quote, ToTokens};
@@ -48,6 +48,7 @@
Api::Enum(enm) => check_api_enum(cx, enm),
Api::CxxType(ety) | Api::RustType(ety) => check_api_type(cx, ety),
Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
+ Api::Impl(imp) => check_api_impl(cx, imp),
_ => {}
}
}
@@ -286,6 +287,18 @@
check_multiple_arg_lifetimes(cx, efn);
}
+fn check_api_impl(cx: &mut Check, imp: &Impl) {
+ if let Type::UniquePtr(ty) | Type::CxxVector(ty) = &imp.ty {
+ if let Type::Ident(inner) = &ty.inner {
+ if Atom::from(inner).is_none() {
+ return;
+ }
+ }
+ }
+
+ cx.error(imp, "unsupported Self type of explicit impl");
+}
+
fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
match &efn.ret {
Some(Type::Ref(ty)) if ty.mutability.is_some() => {}
diff --git a/syntax/file.rs b/syntax/file.rs
index 8b86adc..931ce6e 100644
--- a/syntax/file.rs
+++ b/syntax/file.rs
@@ -2,8 +2,8 @@
use quote::quote;
use syn::parse::{Error, Parse, ParseStream, Result};
use syn::{
- braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemStruct,
- ItemUse, LitStr, Token, Visibility,
+ braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemImpl,
+ ItemStruct, ItemUse, LitStr, Token, Visibility,
};
pub struct Module {
@@ -22,6 +22,7 @@
Enum(ItemEnum),
ForeignMod(ItemForeignMod),
Use(ItemUse),
+ Impl(ItemImpl),
Other(RustItem),
}
@@ -99,6 +100,7 @@
brace_token: item.brace_token,
items: item.items,
})),
+ RustItem::Impl(item) => Ok(Item::Impl(ItemImpl { attrs, ..item })),
RustItem::Use(item) => Ok(Item::Use(ItemUse { attrs, ..item })),
other => Ok(Item::Other(other)),
}
diff --git a/syntax/ident.rs b/syntax/ident.rs
index 7545e92..74e7799 100644
--- a/syntax/ident.rs
+++ b/syntax/ident.rs
@@ -20,7 +20,7 @@
for api in apis {
match api {
- Api::Include(_) => {}
+ Api::Include(_) | Api::Impl(_) => {}
Api::Struct(strct) => {
check(cx, &strct.ident);
for field in &strct.fields {
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 8ef3c8b..934f6c6 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -42,6 +42,7 @@
RustType(ExternType),
RustFunction(ExternFn),
TypeAlias(TypeAlias),
+ Impl(Impl),
}
pub struct ExternType {
@@ -87,6 +88,12 @@
pub semi_token: Token![;],
}
+pub struct Impl {
+ pub impl_token: Token![impl],
+ pub ty: Type,
+ pub brace_token: Brace,
+}
+
pub struct Signature {
pub unsafety: Option<Token![unsafe]>,
pub fn_token: Token![fn],
diff --git a/syntax/parse.rs b/syntax/parse.rs
index cec818d..49dc26b 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -3,17 +3,17 @@
use crate::syntax::report::Errors;
use crate::syntax::Atom::*;
use crate::syntax::{
- attrs, error, Api, Doc, Enum, ExternFn, ExternType, Lang, Receiver, Ref, Signature, Slice,
- Struct, Ty1, Type, TypeAlias, Var, Variant,
+ attrs, error, Api, Doc, Enum, ExternFn, ExternType, Impl, Lang, Receiver, Ref, Signature,
+ Slice, Struct, Ty1, Type, TypeAlias, Var, Variant,
};
-use proc_macro2::{TokenStream, TokenTree};
+use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use quote::{format_ident, quote, quote_spanned};
use syn::parse::{ParseStream, Parser};
use syn::punctuated::Punctuated;
use syn::{
Abi, Attribute, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
- GenericArgument, Ident, ItemEnum, ItemStruct, LitStr, Pat, PathArguments, Result, ReturnType,
- Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
+ GenericArgument, Ident, ItemEnum, ItemImpl, ItemStruct, LitStr, Pat, PathArguments, Result,
+ ReturnType, Token, Type as RustType, TypeBareFn, TypePath, TypeReference, TypeSlice,
};
pub mod kw {
@@ -33,6 +33,10 @@
Err(err) => cx.push(err),
},
Item::ForeignMod(foreign_mod) => parse_foreign_mod(cx, foreign_mod, &mut apis, trusted),
+ Item::Impl(item) => match parse_impl(item) {
+ Ok(imp) => apis.push(imp),
+ Err(err) => cx.push(err),
+ },
Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
Item::Other(item) => cx.error(item, "unsupported item"),
}
@@ -420,6 +424,37 @@
}
}
+fn parse_impl(imp: ItemImpl) -> Result<Api> {
+ if !imp.items.is_empty() {
+ let mut span = Group::new(Delimiter::Brace, TokenStream::new());
+ span.set_span(imp.brace_token.span);
+ return Err(Error::new_spanned(span, "expected an empty impl block"));
+ }
+
+ let self_ty = &imp.self_ty;
+ if let Some((bang, path, for_token)) = &imp.trait_ {
+ let span = quote!(#bang #path #for_token #self_ty);
+ return Err(Error::new_spanned(
+ span,
+ "unexpected impl, expected something like `impl UniquePtr<T> {}`",
+ ));
+ }
+
+ let generics = &imp.generics;
+ if !generics.params.is_empty() || generics.where_clause.is_some() {
+ return Err(Error::new_spanned(
+ imp,
+ "generic parameters on an impl is not supported",
+ ));
+ }
+
+ Ok(Api::Impl(Impl {
+ impl_token: imp.impl_token,
+ ty: parse_type(&self_ty)?,
+ brace_token: imp.brace_token,
+ }))
+}
+
fn parse_include(input: ParseStream) -> Result<String> {
if input.peek(LitStr) {
return Ok(input.parse::<LitStr>()?.value());
diff --git a/syntax/tokens.rs b/syntax/tokens.rs
index 4ed264a..7618e99 100644
--- a/syntax/tokens.rs
+++ b/syntax/tokens.rs
@@ -1,7 +1,7 @@
use crate::syntax::atom::Atom::*;
use crate::syntax::{
- Atom, Derive, Enum, ExternFn, ExternType, Receiver, Ref, Signature, Slice, Struct, Ty1, Type,
- TypeAlias, Var,
+ Atom, Derive, Enum, ExternFn, ExternType, Impl, Receiver, Ref, Signature, Slice, Struct, Ty1,
+ Type, TypeAlias, Var,
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote_spanned, ToTokens};
@@ -121,6 +121,14 @@
}
}
+impl ToTokens for Impl {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.impl_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.brace_token.surround(tokens, |_tokens| {});
+ }
+}
+
impl ToTokens for Signature {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.fn_token.to_tokens(tokens);
diff --git a/syntax/types.rs b/syntax/types.rs
index 6924a78..2afce25 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -15,6 +15,7 @@
pub aliases: Map<&'a Ident, &'a TypeAlias>,
pub untrusted: Map<&'a Ident, &'a ExternType>,
pub required_trivial: Map<&'a Ident, TrivialReason<'a>>,
+ pub explicit_impls: Set<&'a Type>,
}
impl<'a> Types<'a> {
@@ -26,6 +27,7 @@
let mut rust = Set::new();
let mut aliases = Map::new();
let mut untrusted = Map::new();
+ let mut explicit_impls = Set::new();
fn visit<'a>(all: &mut Set<&'a Type>, ty: &'a Type) {
all.insert(ty);
@@ -133,6 +135,10 @@
cxx.insert(ident);
aliases.insert(ident, alias);
}
+ Api::Impl(imp) => {
+ visit(&mut all, &imp.ty);
+ explicit_impls.insert(&imp.ty);
+ }
}
}
@@ -179,6 +185,7 @@
aliases,
untrusted,
required_trivial,
+ explicit_impls,
}
}