From 787d3aa450008643fb9183362aecd057ef6e2043 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 9 Nov 2011 18:54:23 +0300 Subject: [PATCH] New type checking algorithm is used for subtyping constraint generation --- .../jet/lang/resolve/calls/CallResolver.java | 4 +- .../jet/lang/types/JetTypeChecker.java | 396 ++++++++++-------- ...tSystem.java => ConstraintSystemImpl.java} | 102 ++--- .../EqualityBasedConstraintSystem.java | 55 --- 4 files changed, 254 insertions(+), 303 deletions(-) rename compiler/frontend/src/org/jetbrains/jet/lang/types/inference/{SubtypingOnlyConstraintSystem.java => ConstraintSystemImpl.java} (87%) delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 1d95508cfe9..741424efbab 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -21,7 +21,7 @@ import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.inference.ConstraintSystem; import org.jetbrains.jet.lang.types.inference.ConstraintSystemSolution; -import org.jetbrains.jet.lang.types.inference.SubtypingOnlyConstraintSystem; +import org.jetbrains.jet.lang.types.inference.ConstraintSystemImpl; import org.jetbrains.jet.lexer.JetTokens; import java.util.*; @@ -414,7 +414,7 @@ public class CallResolver { if (!candidate.getTypeParameters().isEmpty()) { // Type argument inference - ConstraintSystem constraintSystem = new SubtypingOnlyConstraintSystem(); + ConstraintSystem constraintSystem = new ConstraintSystemImpl(); for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) { constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 38ee84c2f52..6573f54fc19 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -4,8 +4,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import java.util.*; +import java.util.List; +import static org.jetbrains.jet.lang.types.Variance.INVARIANT; import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE; import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE; @@ -21,7 +22,7 @@ public class JetTypeChecker { public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { // return new TypeCheckingProcedure().run(subtype, supertype); - return new ExplicitInOutTypeCheckingProcedure().run(subtype, supertype); + return TYPE_CHECKER.run(subtype, supertype); } // This method returns the supertype of the first parameter that has the same constructor @@ -51,7 +52,39 @@ public class JetTypeChecker { return isOutProjected ? JetStandardClasses.getNothingType() : argument.getType(); } - private static class ExplicitInOutTypeCheckingProcedure { + /** + * Methods of this class return true to continue type checking and false to fail + */ + public interface TypingConstraintBuilder { + boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b); + boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype); + boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype); + } + + private static final TypeCheckingProcedure TYPE_CHECKER = new TypeCheckingProcedure(new TypingConstraintBuilder() { + @Override + public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) { + return TypeUtils.equalTypes(a, b); + } + + @Override + public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype) { + return INSTANCE.isSubtypeOf(subtype, supertype); + } + + @Override + public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { + return false; // type checking fails + } + }); + + public static class TypeCheckingProcedure { + + private final TypingConstraintBuilder constraintBuilder; + + public TypeCheckingProcedure(TypingConstraintBuilder constraintBuilder) { + this.constraintBuilder = constraintBuilder; + } public boolean run(@NotNull JetType subtype, @NotNull JetType supertype) { return isSubtypeOf(subtype, supertype); @@ -69,7 +102,7 @@ public class JetTypeChecker { } @Nullable JetType closestSupertype = findCorrespondingSupertype(subtype, supertype); if (closestSupertype == null) { - return false; + if (!constraintBuilder.noCorrespondingSupertype(subtype, supertype)) return false; } return checkSubtypeForTheSameConstructor(closestSupertype, supertype); @@ -84,6 +117,7 @@ public class JetTypeChecker { List parameters = constructor.getParameters(); for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { TypeParameterDescriptor parameter = parameters.get(i); + TypeProjection subArgument = subArguments.get(i); JetType subIn = getInType(parameter, subArgument); @@ -93,189 +127,193 @@ public class JetTypeChecker { JetType superIn = getInType(parameter, superArgument); JetType superOut = getOutType(parameter, superArgument); - if (!isSubtypeOf(subOut, superOut) || !isSubtypeOf(superIn, subIn)) { - return false; + if (parameter.getVariance() == INVARIANT && subArgument.getProjectionKind() == INVARIANT && superArgument.getProjectionKind() == INVARIANT) { + if (!constraintBuilder.assertEqualTypes(subArgument.getType(), superArgument.getType())) return false; + } + else { + if (!constraintBuilder.assertSubtype(subOut, superOut)) return false; + if (!constraintBuilder.assertSubtype(superIn, subIn)) return false; } } return true; } } - public static abstract class AbstractTypeCheckingProcedure { - - protected enum StatusAction { - PROCEED(false), - DONE_WITH_CURRENT_TYPE(true), - ABORT_ALL(true); - - private final boolean abort; - - private StatusAction(boolean abort) { - this.abort = abort; - } - - public boolean isAbort() { - return abort; - } - } - - public final T run(@NotNull JetType subtype, @NotNull JetType supertype) { - proceedOrStop(subtype, supertype); - return result(); - } - - protected abstract StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype); - - protected abstract StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype); - - protected abstract StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType); - - protected abstract StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument); - - protected abstract StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype); - - protected abstract T result(); - - private StatusAction proceedOrStop(@NotNull JetType subtype, @NotNull JetType supertype) { - StatusAction statusAction = startForPairOfTypes(subtype, supertype); - if (statusAction.isAbort()) { - return statusAction; - } - - JetType closestSupertype = findCorrespondingSupertype(subtype, supertype); - if (closestSupertype == null) { - return noCorrespondingSupertype(subtype, supertype); - } - - proceed(closestSupertype, supertype); - return doneForPairOfTypes(subtype, supertype); - } - - private void proceed(@NotNull JetType subtype, @NotNull JetType supertype) { - TypeConstructor constructor = subtype.getConstructor(); - assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor(); - - List subArguments = subtype.getArguments(); - List superArguments = supertype.getArguments(); - List parameters = constructor.getParameters(); - - loop: - for (int i = 0; i < parameters.size(); i++) { - TypeParameterDescriptor parameter = parameters.get(i); - TypeProjection subArgument = subArguments.get(i); - TypeProjection superArgument = superArguments.get(i); - - JetType subArgumentType = subArgument.getType(); - JetType superArgumentType = superArgument.getType(); - - StatusAction action = null; - switch (parameter.getVariance()) { - case INVARIANT: - switch (superArgument.getProjectionKind()) { - case INVARIANT: - action = equalTypesRequired(subArgumentType, superArgumentType); - break; - case OUT_VARIANCE: - if (!subArgument.getProjectionKind().allowsOutPosition()) { - action = varianceConflictFound(subArgument, superArgument); - } - else { - action = proceedOrStop(subArgumentType, superArgumentType); - } - break; - case IN_VARIANCE: - if (!subArgument.getProjectionKind().allowsInPosition()) { - action = varianceConflictFound(subArgument, superArgument); - } - else { - action = proceedOrStop(superArgumentType, subArgumentType); - } - break; - } - break; - case IN_VARIANCE: - switch (superArgument.getProjectionKind()) { - case INVARIANT: - case IN_VARIANCE: - action = proceedOrStop(superArgumentType, subArgumentType); - break; - case OUT_VARIANCE: - action = proceedOrStop(subArgumentType, superArgumentType); - break; - } - break; - case OUT_VARIANCE: - switch (superArgument.getProjectionKind()) { - case INVARIANT: - case OUT_VARIANCE: - case IN_VARIANCE: - action = proceedOrStop(subArgumentType, superArgumentType); - break; - } - break; - } - switch (action) { - case ABORT_ALL: break loop; - case DONE_WITH_CURRENT_TYPE: - default: - } - } - } - - } +// public static abstract class AbstractTypeCheckingProcedure { +// +// protected enum StatusAction { +// PROCEED(false), +// DONE_WITH_CURRENT_TYPE(true), +// ABORT_ALL(true); +// +// private final boolean abort; +// +// private StatusAction(boolean abort) { +// this.abort = abort; +// } +// +// public boolean isAbort() { +// return abort; +// } +// } +// +// public final T run(@NotNull JetType subtype, @NotNull JetType supertype) { +// proceedOrStop(subtype, supertype); +// return result(); +// } +// +// protected abstract StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype); +// +// protected abstract StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype); +// +// protected abstract StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType); +// +// protected abstract StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument); +// +// protected abstract StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype); +// +// protected abstract T result(); +// +// private StatusAction proceedOrStop(@NotNull JetType subtype, @NotNull JetType supertype) { +// StatusAction statusAction = startForPairOfTypes(subtype, supertype); +// if (statusAction.isAbort()) { +// return statusAction; +// } +// +// JetType closestSupertype = findCorrespondingSupertype(subtype, supertype); +// if (closestSupertype == null) { +// return noCorrespondingSupertype(subtype, supertype); +// } +// +// proceed(closestSupertype, supertype); +// return doneForPairOfTypes(subtype, supertype); +// } +// +// private void proceed(@NotNull JetType subtype, @NotNull JetType supertype) { +// TypeConstructor constructor = subtype.getConstructor(); +// assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor(); +// +// List subArguments = subtype.getArguments(); +// List superArguments = supertype.getArguments(); +// List parameters = constructor.getParameters(); +// +// loop: +// for (int i = 0; i < parameters.size(); i++) { +// TypeParameterDescriptor parameter = parameters.get(i); +// TypeProjection subArgument = subArguments.get(i); +// TypeProjection superArgument = superArguments.get(i); +// +// JetType subArgumentType = subArgument.getType(); +// JetType superArgumentType = superArgument.getType(); +// +// StatusAction action = null; +// switch (parameter.getVariance()) { +// case INVARIANT: +// switch (superArgument.getProjectionKind()) { +// case INVARIANT: +// action = equalTypesRequired(subArgumentType, superArgumentType); +// break; +// case OUT_VARIANCE: +// if (!subArgument.getProjectionKind().allowsOutPosition()) { +// action = varianceConflictFound(subArgument, superArgument); +// } +// else { +// action = proceedOrStop(subArgumentType, superArgumentType); +// } +// break; +// case IN_VARIANCE: +// if (!subArgument.getProjectionKind().allowsInPosition()) { +// action = varianceConflictFound(subArgument, superArgument); +// } +// else { +// action = proceedOrStop(superArgumentType, subArgumentType); +// } +// break; +// } +// break; +// case IN_VARIANCE: +// switch (superArgument.getProjectionKind()) { +// case INVARIANT: +// case IN_VARIANCE: +// action = proceedOrStop(superArgumentType, subArgumentType); +// break; +// case OUT_VARIANCE: +// action = proceedOrStop(subArgumentType, superArgumentType); +// break; +// } +// break; +// case OUT_VARIANCE: +// switch (superArgument.getProjectionKind()) { +// case INVARIANT: +// case OUT_VARIANCE: +// case IN_VARIANCE: +// action = proceedOrStop(subArgumentType, superArgumentType); +// break; +// } +// break; +// } +// switch (action) { +// case ABORT_ALL: break loop; +// case DONE_WITH_CURRENT_TYPE: +// default: +// } +// } +// } +// +// } - private static class TypeCheckingProcedure extends AbstractTypeCheckingProcedure { - - private boolean result = true; - - private StatusAction fail() { - result = false; - return StatusAction.ABORT_ALL; - } - - @Override - public StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { - if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) { - return StatusAction.DONE_WITH_CURRENT_TYPE; - } - if (!supertype.isNullable() && subtype.isNullable()) { - return fail(); - } - if (JetStandardClasses.isNothingOrNullableNothing(subtype)) { - return StatusAction.DONE_WITH_CURRENT_TYPE; - } - return StatusAction.PROCEED; - } - - @Override - protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { - return fail(); - } - - @Override - protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) { - if (!subArgumentType.equals(superArgumentType)) { - return fail(); - } - return StatusAction.PROCEED; - } - - @Override - protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) { - return fail(); - } - - @Override - protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { - return StatusAction.PROCEED; - } - - @Override - protected Boolean result() { - return result; - } - } +// private static class TypeCheckingProcedure extends AbstractTypeCheckingProcedure { +// +// private boolean result = true; +// +// private StatusAction fail() { +// result = false; +// return StatusAction.ABORT_ALL; +// } +// +// @Override +// public StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { +// if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) { +// return StatusAction.DONE_WITH_CURRENT_TYPE; +// } +// if (!supertype.isNullable() && subtype.isNullable()) { +// return fail(); +// } +// if (JetStandardClasses.isNothingOrNullableNothing(subtype)) { +// return StatusAction.DONE_WITH_CURRENT_TYPE; +// } +// return StatusAction.PROCEED; +// } +// +// @Override +// protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { +// return fail(); +// } +// +// @Override +// protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) { +// if (!subArgumentType.equals(superArgumentType)) { +// return fail(); +// } +// return StatusAction.PROCEED; +// } +// +// @Override +// protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) { +// return fail(); +// } +// +// @Override +// protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { +// return StatusAction.PROCEED; +// } +// +// @Override +// protected Boolean result() { +// return result; +// } +// } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/SubtypingOnlyConstraintSystem.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemImpl.java similarity index 87% rename from compiler/frontend/src/org/jetbrains/jet/lang/types/inference/SubtypingOnlyConstraintSystem.java rename to compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemImpl.java index 5ebe51309f8..fc7e403dd5b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/SubtypingOnlyConstraintSystem.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/ConstraintSystemImpl.java @@ -14,7 +14,7 @@ import java.util.Set; /** * @author abreslav */ -public class SubtypingOnlyConstraintSystem implements ConstraintSystem { +public class ConstraintSystemImpl implements ConstraintSystem { private static class LoopInTypeVariableConstraintsException extends RuntimeException { private LoopInTypeVariableConstraintsException() { @@ -158,6 +158,39 @@ public class SubtypingOnlyConstraintSystem implements ConstraintSystem { private final Map unknownTypes = Maps.newHashMap(); private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + private final JetTypeChecker.TypeCheckingProcedure constraintExpander = new JetTypeChecker.TypeCheckingProcedure(new JetTypeChecker.TypingConstraintBuilder() { + @Override + public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b) { + return TypeUtils.equalTypes(a, b); + } + + @Override + public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype) { + TypeValue subtypeValue = getTypeValueFor(subtype); + TypeValue supertypeValue = getTypeValueFor(supertype); + + if (someUnknown(subtypeValue, supertypeValue)) { + addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue); + } + return true; + } + + @Override + public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { + // If some of the types is an unknown, the constraint is already generated, and we should carry on + // otherwise there can be no solution, and we should fail + return someUnknown(getTypeValueFor(subtype), getTypeValueFor(supertype)); + } + + private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) { + return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType; + } + + }); + + public ConstraintSystemImpl() { + } + @NotNull private TypeValue getTypeValueFor(@NotNull JetType type) { DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); @@ -217,7 +250,7 @@ public class SubtypingOnlyConstraintSystem implements ConstraintSystem { for (TypeValue upperBound : typeValue.getUpperBounds()) { if (upperBound instanceof KnownType) { KnownType knownBoundType = (KnownType) upperBound; - boolean ok = new SubtypingConstraintExpander().run(jetType, knownBoundType.getType()); + boolean ok = constraintExpander.run(jetType, knownBoundType.getType()); if (!ok) { return new Solution(true); } @@ -344,72 +377,7 @@ public class SubtypingOnlyConstraintSystem implements ConstraintSystem { } -// private class EqualityConstraintExpander extends JetTypeChecker.AbstractTypeCheckingProcedure { -// -// } - - private class SubtypingConstraintExpander extends JetTypeChecker.AbstractTypeCheckingProcedure { - - private boolean error = false; - - private StatusAction fail() { - error = true; - return StatusAction.ABORT_ALL; - } - - @Override - protected StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { - return tryToAddConstraint(subtype, supertype); - } - - private StatusAction tryToAddConstraint(@NotNull JetType subtype, @NotNull JetType supertype) { - TypeValue subtypeValue = getTypeValueFor(subtype); - TypeValue supertypeValue = getTypeValueFor(supertype); - - if (someUnknown(subtypeValue, supertypeValue)) { - addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue); - } - return StatusAction.PROCEED; - } - - private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) { - return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType; - } - - @Override - protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { - if (someUnknown(getTypeValueFor(subtype), getTypeValueFor(supertype))) { - return StatusAction.PROCEED; - } - return fail(); - } - - @Override - protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) { - if (!subArgumentType.equals(superArgumentType)) { - return fail(); - } - return StatusAction.PROCEED; - } - - @Override - protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) { - return fail(); - } - - @Override - protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { - return StatusAction.PROCEED; - } - - @Override - protected Boolean result() { - return !error; - } - } - private static void println(String message) { // System.out.println(message); } - } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java deleted file mode 100644 index 3a4b25cf0a4..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/inference/EqualityBasedConstraintSystem.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.jetbrains.jet.lang.types.inference; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.Variance; - -import java.util.List; -import java.util.Map; - -/** - * @author abreslav - */ -public class EqualityBasedConstraintSystem implements ConstraintSystem { - - private abstract class Constraint { - private final TypeParameterDescriptor typeParameterDescriptor; - - protected Constraint(@NotNull TypeParameterDescriptor typeParameterDescriptor) { - this.typeParameterDescriptor = typeParameterDescriptor; - } - - @NotNull - public TypeParameterDescriptor getTypeParameterDescriptor() { - return typeParameterDescriptor; - } - } - - private class Unknown { - // T -> variance of its position - private final Map typeParameters = Maps.newHashMap(); - private final List constraints = Lists.newArrayList(); - - } - - private final Map unknowns = Maps.newHashMap(); - - @Override - public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) { - throw new UnsupportedOperationException(); // TODO - } - - @Override - public void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper) { - throw new UnsupportedOperationException(); // TODO - } - - @NotNull - @Override - public ConstraintSystemSolution solve() { - throw new UnsupportedOperationException(); // TODO - } -}