@Test
 public void memberAccessFailsIfLeftHandExpressionIsNotScalarType() {
   Type type = Types.newUnknown();
   context.add(declaration, unassignableValue(type));
   MemberAccessNode memberAccess = Nodes.member(reference, "height");
   TypeResult<ValueInfo> result = inferValueInfo(memberAccess);
   assertThat(result, isFailureWithErrors(new NotScalarTypeError(type)));
 }
 @Test
 public void memberAccessFailsIfInterfaceDoesNotHaveSpecifiedMember() {
   InterfaceType interfaceType =
       new InterfaceType(fullyQualifiedName("shed", "example", "Brother"));
   context.add(declaration, unassignableValue(interfaceType));
   context.addInfo(
       interfaceType,
       new ScalarTypeInfo(interfaces(), members("age", unassignableValue(CoreTypes.DOUBLE))));
   MemberAccessNode memberAccess = Nodes.member(reference, "height");
   TypeResult<ValueInfo> result = inferValueInfo(memberAccess);
   assertThat(errorStrings(result), is(asList("No such member: height")));
 }
  @Test
  public void memberAccessIsAssignableIfMemberIsAssignable() {
    InterfaceType interfaceType =
        new InterfaceType(fullyQualifiedName("shed", "example", "Brother"));
    context.add(declaration, unassignableValue(interfaceType));
    context.addInfo(
        interfaceType,
        new ScalarTypeInfo(interfaces(), members("age", assignableValue(CoreTypes.DOUBLE))));

    MemberAccessNode memberAccess = Nodes.member(reference, "age");
    TypeResult<ValueInfo> result = inferValueInfo(memberAccess);
    assertThat(result, isSuccessWithValue(assignableValue(CoreTypes.DOUBLE)));
  }
public class FunctionSignatureDeclarationTypeCheckerTest {
  private final TypeCheckerTestFixture fixture = TypeCheckerTestFixture.build();
  private final FunctionSignatureDeclarationNode funcSignature =
      Nodes.funcSignature(
          "alert",
          asList(Nodes.formalArgument("string", fixture.stringTypeReference())),
          fixture.unitTypeReference());;

  @Test
  public void forwardDeclaringAddsFunctionSignatureToContext() {
    TypeResult<?> result = forwardDeclare(funcSignature);

    assertThat(result, isSuccess());
    Type functionType = fixture.context().getTypeOf(funcSignature).get();
    assertThat(functionType, is((Type) CoreTypes.functionTypeOf(CoreTypes.STRING, CoreTypes.UNIT)));
  }

  @Test
  public void functionSignatureDoesNotReturn() {
    TypeResult<StatementTypeCheckResult> result = typeCheck(funcSignature);

    assertThat(result, isSuccessWithValue(StatementTypeCheckResult.noReturn()));
  }

  private TypeResult<?> forwardDeclare(FunctionSignatureDeclarationNode declaration) {
    return typeChecker().forwardDeclare(declaration);
  }

  private TypeResult<StatementTypeCheckResult> typeCheck(
      FunctionSignatureDeclarationNode declaration) {
    return typeChecker().typeCheck(declaration, Option.<Type>none());
  }

  private FunctionSignatureDeclarationTypeChecker typeChecker() {
    return fixture.get(FunctionSignatureDeclarationTypeChecker.class);
  }
}
 @Test
 public void canInferTypeOfUnitLiteralsAsUnit() {
   assertThat(inferType(Nodes.unit()), isType(CoreTypes.UNIT));
 }
public class MemberAccessTypeInfererTest {
  private final TypeCheckerTestFixture fixture = TypeCheckerTestFixture.build();
  private final StaticContext context = fixture.context();
  private final VariableIdentifierNode reference = Nodes.id("heAintHeavy");
  private final GlobalDeclaration declaration = globalDeclaration("heAintHeavy");

  public MemberAccessTypeInfererTest() {
    fixture.addReference(reference, declaration);
  }

  @Test
  public void memberAccessHasTypeOfMember() {
    InterfaceType interfaceType =
        new InterfaceType(fullyQualifiedName("shed", "example", "Brother"));
    context.add(declaration, unassignableValue(interfaceType));
    context.addInfo(
        interfaceType,
        new ScalarTypeInfo(interfaces(), members("age", unassignableValue(CoreTypes.DOUBLE))));

    MemberAccessNode memberAccess = Nodes.member(reference, "age");
    TypeResult<ValueInfo> result = inferValueInfo(memberAccess);
    assertThat(result, isSuccessWithValue(unassignableValue(CoreTypes.DOUBLE)));
  }

  @Test
  public void memberAccessIsAssignableIfMemberIsAssignable() {
    InterfaceType interfaceType =
        new InterfaceType(fullyQualifiedName("shed", "example", "Brother"));
    context.add(declaration, unassignableValue(interfaceType));
    context.addInfo(
        interfaceType,
        new ScalarTypeInfo(interfaces(), members("age", assignableValue(CoreTypes.DOUBLE))));

    MemberAccessNode memberAccess = Nodes.member(reference, "age");
    TypeResult<ValueInfo> result = inferValueInfo(memberAccess);
    assertThat(result, isSuccessWithValue(assignableValue(CoreTypes.DOUBLE)));
  }

  @Test
  public void memberAccessFailsIfInterfaceDoesNotHaveSpecifiedMember() {
    InterfaceType interfaceType =
        new InterfaceType(fullyQualifiedName("shed", "example", "Brother"));
    context.add(declaration, unassignableValue(interfaceType));
    context.addInfo(
        interfaceType,
        new ScalarTypeInfo(interfaces(), members("age", unassignableValue(CoreTypes.DOUBLE))));
    MemberAccessNode memberAccess = Nodes.member(reference, "height");
    TypeResult<ValueInfo> result = inferValueInfo(memberAccess);
    assertThat(errorStrings(result), is(asList("No such member: height")));
  }

  @Test
  public void memberAccessFailsIfLeftHandExpressionIsNotScalarType() {
    Type type = Types.newUnknown();
    context.add(declaration, unassignableValue(type));
    MemberAccessNode memberAccess = Nodes.member(reference, "height");
    TypeResult<ValueInfo> result = inferValueInfo(memberAccess);
    assertThat(result, isFailureWithErrors(new NotScalarTypeError(type)));
  }

  private TypeResult<ValueInfo> inferValueInfo(MemberAccessNode expression) {
    return fixture.get(MemberAccessTypeInferer.class).inferValueInfo(expression);
  }
}