blob: 6a9bff610ecee389666b942d3771f4dda786baff [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package groovy.transform.stc
import groovy.transform.CompileStatic
/**
* Unit tests for static type checking : loops.
*/
class LoopsSTCTest extends StaticTypeCheckingTestCase {
void testMethodCallInLoop() {
assertScript '''
int foo(int x) { x+1 }
int x = 0
for (int i=0;i<10;i++) {
x = foo(x)
}
'''
}
void testMethodCallInLoopAndDef() {
assertScript '''
int foo(int x) { x+1 }
def x = 0
for (int i=0;i<10;i++) {
x = foo(x)
}
'''
}
// GROOVY-8882
void testStringCollectionLoop() {
for (char c in 'abc') assert c instanceof Character
for (Character c in 'abc') assert c instanceof Character
for (String s in 'abc') assert s instanceof String
for (s in 'abc') assert s instanceof String
}
// GROOVY-8882
@CompileStatic
void testStringCollectionLoopCS() {
for (char c in 'abc') assert c instanceof Character
for (Character c in 'abc') assert c instanceof Character
for (String s in 'abc') assert s instanceof String
for (s in 'abc') assert s instanceof String
}
void testMethodCallWithEachAndDefAndTwoFooMethods() {
shouldFailWithMessages '''
Date foo(Integer x) { new Date() }
Integer foo(Date x) { 1 }
def x = 0
10.times {
// there are two possible target methods. This is not a problem for STC, but it is for static compilation
x = foo(x)
}
''', 'Cannot find matching method'
}
void testMethodCallInLoopAndDefAndTwoFooMethods() {
shouldFailWithMessages '''
Date foo(Integer x) { new Date() }
Integer foo(Date x) { 1 }
def x = 0
for (int i=0;i<10;i++) {
// there are two possible target methods. This is not a problem for STC, but it is for static compilation
x = foo(x)
}
''', 'Cannot find matching method'
}
void testMethodCallInLoopAndDefAndTwoFooMethodsAndOneWithBadType() {
shouldFailWithMessages '''
Double foo(Integer x) { x+1 }
Date foo(Double x) { new Date((long)x) }
def x = 0
for (int i=0;i<10;i++) {
// there are two possible target methods and one returns a type which is assigned to 'x'
// then called in turn as a parameter of foo(). There's no #foo(Date)
x = foo(x)
}
''', 'Cannot find matching method'
}
void testMethodCallInLoopAndDefAndTwoFooMethodsAndOneWithBadTypeAndIndirection() {
shouldFailWithMessages '''
Double foo(Integer x) { x+1 }
Date foo(Double x) { new Date((long)x) }
def x = 0
for (int i=0;i<10;i++) {
def y = foo(x)
// there are two possible target methods and one returns a type which is assigned to 'x'
// then called in turn as a parameter of foo(). There's no #foo(Date)
x = y
}
''', 'Cannot find matching method'
}
void testMethodCallWithEachAndDefAndTwoFooMethodsAndOneWithBadTypeAndIndirection() {
shouldFailWithMessages '''
Double foo(Integer x) { x+1 }
Date foo(Double x) { new Date((long)x) }
def x = 0
10.times {
def y = foo(x)
// there are two possible target methods and one returns a type which is assigned to 'x'
// then called in turn as a parameter of foo(). There's no #foo(Date)
x = y
}
''', 'Cannot find matching method'
}
// GROOVY-5587
void testMapEntryInForInLoop() {
assertScript '''
@ASTTest(phase=INSTRUCTION_SELECTION, value= {
lookup('forLoop').each {
assert it instanceof org.codehaus.groovy.ast.stmt.ForStatement
def collection = it.collectionExpression // MethodCallExpression
def inft = collection.getNodeMetaData(INFERRED_TYPE)
assert inft == make(Set)
def entryInft = inft.genericsTypes[0].type
assert entryInft == make(Map.Entry)
assert entryInft.genericsTypes[0].type == STRING_TYPE
assert entryInft.genericsTypes[1].type == Integer_TYPE
}
})
void test() {
def result = ""
def sum = 0
forLoop:
for ( Map.Entry<String, Integer> it in [a:1, b:3].entrySet() ) {
result += it.getKey()
sum += it.getValue()
}
assert result == "ab"
assert sum == 4
}
test()
'''
}
void testShouldNotInferSoftReferenceAsComponentType() {
assertScript '''import java.lang.reflect.Field
import org.codehaus.groovy.ast.stmt.ForStatement
@ASTTest(phase=INSTRUCTION_SELECTION, value= {
def FIELD_ARRAY = make(Field).makeArray()
def forStmt = lookup('myLoop')[0]
assert forStmt instanceof ForStatement
def collectionType = forStmt.collectionExpression.getNodeMetaData(INFERRED_TYPE)
assert collectionType == FIELD_ARRAY
})
void forInTest() {
int i = 0;
myLoop:
for (def field : String.class.declaredFields) {
i++;
}
assert i > 0
}
'''
}
// GROOVY-5640
void testShouldInferComponentTypeAsIterableOfNodes() {
assertScript '''import org.codehaus.groovy.ast.stmt.ForStatement
class Node {}
interface Traverser {
Iterable<Node> nodes()
}
class MyTraverser implements Traverser {
Iterable<Node> nodes() {
[]
}
}
@ASTTest(phase=INSTRUCTION_SELECTION, value= {
def forStmt = lookup('loop')[0]
assert forStmt instanceof ForStatement
def collectionType = forStmt.collectionExpression.getNodeMetaData(INFERRED_TYPE)
assert collectionType == make(Iterable)
assert collectionType.isUsingGenerics()
assert collectionType.genericsTypes.length == 1
assert collectionType.genericsTypes[0].type.name == 'Node'
})
void test() {
loop:
for (def node : new MyTraverser().nodes()) {
println node.class.name
}
}
'''
}
// GROOVY-5641
void testShouldInferLoopElementTypeWithUndeclaredType() {
assertScript '''import org.codehaus.groovy.ast.stmt.ForStatement
@ASTTest(phase=INSTRUCTION_SELECTION, value= {
def forStmt = lookup('loop')[0]
assert forStmt instanceof ForStatement
def collectionType = forStmt.collectionExpression.getNodeMetaData(INFERRED_TYPE)
assert collectionType == make(IntRange)
})
void foo() {
int[] perm = new int[10]
loop:
for (i in 0..<10) {
assert perm[i-0] == 0
}
}
'''
}
}