Using 'interface' and 'abstract' for methods should produce error

R=brianwilkerson@google.com
BUG=

Review URL: https://codereview.chromium.org//11314019

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@14165 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
scheglov@google.com
2012-10-27 16:22:18 +00:00
parent dbec5629e8
commit dce51bf910
37 changed files with 274 additions and 1630 deletions
@@ -332,6 +332,13 @@ public class DartParser extends CompletionHooksParserBase {
} else if (peekPseudoKeyword(0, INTERFACE_KEYWORD) && peek(1).equals(Token.IDENTIFIER)) {
consume(Token.IDENTIFIER);
isParsingInterface = true;
// TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6318
if (!Elements.isCoreLibrarySource(source)
&& !Elements.isLibrarySource(source, "/isolate/isolate.dart")
&& !Elements.isLibrarySource(source, "crypto/crypto.dart")
&& !Elements.isDart2JsLibrarySource(source)) {
reportError(position(), ParserErrorCode.DEPRECATED_INTERFACE);
}
node = done(parseClass());
} else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
&& (peek(1).equals(Token.IDENTIFIER) || peek(1).equals(Token.VOID) || peek(1).equals(Token.AS))) {
@@ -1258,9 +1265,6 @@ public class DartParser extends CompletionHooksParserBase {
}
}
if (optionalPseudoKeyword(ABSTRACT_KEYWORD)) {
if (isParsingInterface) {
reportError(position(), ParserErrorCode.ABSTRACT_MEMBER_IN_INTERFACE);
}
if (modifiers.isStatic()) {
reportError(position(), ParserErrorCode.STATIC_MEMBERS_CANNOT_BE_ABSTRACT);
}
@@ -1291,6 +1295,22 @@ public class DartParser extends CompletionHooksParserBase {
reportError(position(), ParserErrorCode.DISALLOWED_FACTORY_KEYWORD);
}
}
// report "abstract" warning after all other checks to don't hide error with warning
// we ignore problems if there was already reported problem after given position
if (modifiers.isAbstract()) {
// TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6322
// TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6323
if (!Elements.isCoreLibrarySource(source)
&& !Elements.isLibrarySource(source, "html/dartium/html_dartium.dart")
&& !Elements.isLibrarySource(source, "/math/math.dart")
&& !Elements.isLibrarySource(source, "/io/io_runtime.dart")
&& !Elements.isLibrarySource(source, "/crypto/crypto.dart")
&& !Elements.isLibrarySource(source, "/utf/utf.dart")
&& !Elements.isDart2JsLibrarySource(source)) {
reportError(position(), ParserErrorCode.DEPRECATED_ABSTRACT_METHOD);
}
}
if (modifiers.isFactory()) {
if (!isParsingClass) {
@@ -33,8 +33,10 @@ public enum ParserErrorCode implements ErrorCode {
DEFAULT_POSITIONAL_PARAMETER("Positional parameters cannot have default values"),
DEPRECATED_CATCH("This style of catch clause has been deprecated. Please use the 'on' <type> " +
"'catch' '(' <identifier> (',' <identifier>)? ')' form."),
DEPRECATED_ABSTRACT_METHOD(ErrorSeverity.WARNING, "Modifier 'abstract' is deprecated for methods without body. Remove it."),
DEPRECATED_GETTER("The presence of parentheses after the name of the getter "
+ "has been deprecated and will soon be disallowed. Please remove the parentheses."),
DEPRECATED_INTERFACE("Deprecated declaration of the 'interface', use abstract 'class' instead"),
DEPRECATED_USE_OF_FACTORY_KEYWORD("Deprecated use of the 'factory' keyword: use 'default' instead"),
DEPRECATED_RAW_STRING("The use of '@' to prefix a raw string has been deprecated; use 'r' instead"),
DEPRECATED_RESOURCE_DIRECTIVE("The #resource directive has been deprecated and will soon be disallowed"),
@@ -73,9 +75,9 @@ public enum ParserErrorCode implements ErrorCode {
EXPECTED_TOKEN("Unexpected token '%s' (expected '%s')"),
// TODO(zundel): error message needs JUnit test
EXPECTED_VAR_FINAL_OR_TYPE("Expected 'var', 'final' or type"),
EXTERNAL_ABSTRACT("External methods cannot be abstract"),
EXTERNAL_ONLY_METHOD("Only a top-level function, a method, a getter, a setter or an non-redirecting constructor can be specified as external"),
EXTERNAL_METHOD_BODY("External methods cannot have body"),
EXTERNAL_ABSTRACT("External methods cannot be abstract"),
INVALID_SEPARATOR_FOR_NAMED("Use ':' between a named parameter and its value"),
INVALID_SEPARATOR_FOR_OPTIONAL("Use '=' between an optional parameter and its value"),
// TODO(zundel): this error message is out of date
@@ -727,6 +727,21 @@ static FieldElementImplementation fieldFromNode(DartField node,
}
return false;
}
/**
* @return <code>true</code> if given {@link Source} represents library with given name.
*/
public static boolean isDart2JsLibrarySource(Source source) {
if (source instanceof DartSource) {
DartSource dartSource = (DartSource) source;
LibrarySource library = dartSource.getLibrary();
if (library != null) {
String libraryName = library.getName();
return libraryName.contains("lib/compiler/implementation/");
}
}
return false;
}
/**
* @return <code>true</code> if given {@link Source} represents code library declaration or
@@ -84,7 +84,6 @@ import com.google.dart.compiler.type.Type;
import com.google.dart.compiler.type.TypeKind;
import com.google.dart.compiler.type.TypeVariable;
import com.google.dart.compiler.type.Types;
import com.google.dart.compiler.util.apache.StringUtils;
import java.util.EnumSet;
import java.util.Iterator;
@@ -379,14 +378,6 @@ public class Resolver {
// Make sure the default class matches the interface type parameters
checkInterfaceTypeParamsToDefault(classElement, defaultClass);
// Check that interface constructors have corresponding methods in default class.
checkInterfaceConstructors(classElement);
} else if (classElement.isInterface() && classElement.getConstructors() != null) {
for (ConstructorElement interfaceConstructor : classElement.getConstructors()) {
onError(interfaceConstructor.getNameLocation(),
ResolverErrorCode.ILLEGAL_CONSTRUCTOR_NO_DEFAULT_IN_INTERFACE);
}
}
if (!classElement.isInterface() && Elements.needsImplicitDefaultConstructor(classElement)) {
@@ -549,73 +540,6 @@ public class Resolver {
}
}
/**
* Checks that interface constructors have corresponding methods in default class.
*/
private void checkInterfaceConstructors(ClassElement interfaceElement) {
String interfaceClassName = interfaceElement.getName();
String defaultClassName = interfaceElement.getDefaultClass().getElement().getName();
for (ConstructorElement interfaceConstructor : interfaceElement.getConstructors()) {
ConstructorElement defaultConstructor =
resolveInterfaceConstructorInDefaultClass(
interfaceConstructor,
interfaceConstructor);
if (defaultConstructor != null) {
// Remember for TypeAnalyzer.
interfaceConstructor.setDefaultConstructor(defaultConstructor);
// Validate number of required parameters.
{
int numReqInterface = Elements.getNumberOfRequiredParameters(interfaceConstructor);
int numReqDefault = Elements.getNumberOfRequiredParameters(defaultConstructor);
if (numReqInterface != numReqDefault) {
onError(
interfaceConstructor,
ResolverErrorCode.DEFAULT_CONSTRUCTOR_NUMBER_OF_REQUIRED_PARAMETERS,
Elements.getRawMethodName(interfaceConstructor),
interfaceClassName,
numReqInterface,
Elements.getRawMethodName(defaultConstructor),
defaultClassName,
numReqDefault);
}
}
// Validate number of required parameters.
{
int numInterface = Elements.getNumberOfOptionalPositionalParameters(interfaceConstructor);
int numDefault = Elements.getNumberOfOptionalPositionalParameters(defaultConstructor);
if (numInterface != numDefault) {
onError(
interfaceConstructor,
ResolverErrorCode.DEFAULT_CONSTRUCTOR_OPTIONAL_POSITIONAL_PARAMETERS,
Elements.getRawMethodName(interfaceConstructor),
interfaceClassName,
numInterface,
Elements.getRawMethodName(defaultConstructor),
defaultClassName,
numDefault);
}
}
// Validate names of named parameters.
{
List<String> interfaceNames = Elements.getNamedParameters(interfaceConstructor);
List<String> defaultNames = Elements.getNamedParameters(defaultConstructor);
if (!interfaceNames.equals(defaultNames)) {
onError(
interfaceConstructor,
ResolverErrorCode.DEFAULT_CONSTRUCTOR_NAMED_PARAMETERS,
Elements.getRawMethodName(interfaceConstructor),
interfaceClassName,
interfaceNames,
Elements.getRawMethodName(defaultConstructor),
defaultClassName,
defaultNames);
}
}
}
}
}
/**
* Returns <code>true</code> if the {@link ClassElement} has an implicit or a declared
* default constructor.
@@ -1717,9 +1641,6 @@ public class Resolver {
// Will check that element is not null.
ConstructorElement constructor = checkIsConstructor(x, element);
// try to lookup the constructor in the default class.
constructor = resolveInterfaceConstructorInDefaultClass(x.getConstructor(), constructor);
// Check constructor.
if (constructor != null) {
boolean constConstructor = constructor.getModifiers().isConstant();
@@ -1742,87 +1663,6 @@ public class Resolver {
return recordElement(x, constructor);
}
/**
* If given {@link ConstructorElement} is declared in interface, try to resolve it in
* corresponding default class.
*
* @return the resolved {@link ConstructorElement}, or same as given.
*/
private ConstructorElement resolveInterfaceConstructorInDefaultClass(HasSourceInfo errorTarget,
ConstructorElement constructor) {
// If no default class, use existing constructor.
if (constructor == null || constructor.getConstructorType().getDefaultClass() == null) {
return constructor;
}
// Prepare elements and names for classes.
ClassElement originalClass = constructor.getConstructorType();
ClassElement defaultClass = originalClass.getDefaultClass().getElement();
String originalClassName = originalClass.getName();
String defaultClassName = defaultClass.getName();
// Prepare "qualifier.name" for original constructor.
String rawOriginalMethodName = Elements.getRawMethodName(constructor);
int originalDotIndex = rawOriginalMethodName.indexOf('.');
String originalQualifier = StringUtils.substringBefore(rawOriginalMethodName, ".");
String originalName = StringUtils.substringAfter(rawOriginalMethodName, ".");
// Separate checks for cases when factory implements interface and not.
boolean factoryImplementsInterface = Elements.implementsType(defaultClass, originalClass);
if (factoryImplementsInterface) {
for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
// kI == nI and kF == nF
if (rawOriginalMethodName.equals(originalClassName)
&& rawDefaultMethodName.equals(defaultClassName)) {
return defaultConstructor;
}
// kI == nI.name and kF == nF.name
if (originalDotIndex != -1) {
int defaultDotIndex = rawDefaultMethodName.indexOf('.');
if (defaultDotIndex != -1) {
String defaultQualifier = StringUtils.substringBefore(rawDefaultMethodName, ".");
String defaultName = StringUtils.substringAfter(rawDefaultMethodName, ".");
if (defaultQualifier.equals(defaultClassName)
&& originalQualifier.equals(originalClassName)
&& defaultName.equals(originalName)) {
return defaultConstructor;
}
}
}
}
} else {
for (ConstructorElement defaultConstructor : defaultClass.getConstructors()) {
String rawDefaultMethodName = Elements.getRawMethodName(defaultConstructor);
if (rawDefaultMethodName.equals(rawOriginalMethodName)) {
return defaultConstructor;
}
}
}
// If constructor not found, try implicit default constructor of the default class.
if (Elements.isDefaultConstructor(constructor)
&& (Elements.isSyntheticConstructor(constructor) || factoryImplementsInterface)
&& Elements.needsImplicitDefaultConstructor(defaultClass)) {
return new SyntheticDefaultConstructorElement(null, defaultClass, typeProvider);
}
// Factory constructor not resolved, report error with specific message for each case.
{
String expectedFactoryConstructorName;
if (factoryImplementsInterface) {
if (originalDotIndex == -1) {
expectedFactoryConstructorName = defaultClassName;
} else {
expectedFactoryConstructorName = defaultClassName + "." + originalName;
}
} else {
expectedFactoryConstructorName = rawOriginalMethodName;
}
onError(
errorTarget,
ResolverErrorCode.DEFAULT_CONSTRUCTOR_UNRESOLVED,
expectedFactoryConstructorName,
defaultClassName);
return null;
}
}
@Override
public Element visitGotoStatement(DartGotoStatement x) {
// Don't bother unless there's a target.
@@ -125,8 +125,6 @@ public enum ResolverErrorCode implements ErrorCode {
ILLEGAL_ACCESS_TO_PRIVATE("'%s' is private and not defined in this library"),
// TODO(zundel): error message needs JUnit test - how to test #imports in junit?
ILLEGAL_ACCESS_TO_PRIVATE_MEMBER("\"%s\" refers to \"%s\" which is in a different library"),
ILLEGAL_CONSTRUCTOR_NO_DEFAULT_IN_INTERFACE(
"Illegal constructor declaration. No default clause in interface"),
ILLEGAL_FIELD_ACCESS_FROM_STATIC("Illegal access of instance field %s from static scope"),
ILLEGAL_METHOD_ACCESS_FROM_STATIC("Illegal access of instance method %s from static scope"),
INIT_FIELD_ONLY_IMMEDIATELY_SURROUNDING_CLASS(