//===--- ITCType.cpp - Iterative Type Checker for Types -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
//  This file implements the portions of the IterativeTypeChecker
//  class that involve types.
//
//===----------------------------------------------------------------------===//
#include "GenericTypeResolver.h"
#include "TypeChecker.h"
#include "swift/Sema/IterativeTypeChecker.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
using namespace swift;

//----------------------------------------------------------------------------//
// Type resolution.
//----------------------------------------------------------------------------//
bool IterativeTypeChecker::isResolveTypeReprSatisfied(
       std::tuple<TypeRepr *, DeclContext *, unsigned> payload) {
  auto typeRepr = std::get<0>(payload);
  auto options = static_cast<TypeResolutionOptions>(std::get<2>(payload));

  // FIXME: Introduce a bit indicating when everything in the TypeRepr
  // has been name-bound, which indicates that we can always compute a
  // structural type.
  struct FindUnboundTypeRepr : public ASTWalker {
    TypeResolutionOptions Options;

    // Whether we've found an unbound type.
    bool HasUnbound = false;

    FindUnboundTypeRepr(TypeResolutionOptions options) : Options(options) { }

    bool walkToTypeReprPre(TypeRepr *T) override {
      // If we already found an unbound type, we're done.
      if (HasUnbound) return false;

      if (auto ident = dyn_cast<ComponentIdentTypeRepr>(T)) {
        if (!ident->isBound()) {
          HasUnbound = true;
          return false;
        }

        // If we're only looking to resolve the structure of the type,
        // don't walk into generic arguments. They don't affect the
        // structure.
        if (Options.contains(TR_ResolveStructure) &&
            isa<GenericIdentTypeRepr>(ident))
          return false;
      }

      // Keep walking.
      return true;
    }
  } findUnboundTypeRepr(options);

  typeRepr->walk(findUnboundTypeRepr);
  return findUnboundTypeRepr.HasUnbound;
}

void IterativeTypeChecker::processResolveTypeRepr(
       std::tuple<TypeRepr *, DeclContext *, unsigned> payload,
       UnsatisfiedDependency unsatisfiedDependency) {
  auto typeRepr = std::get<0>(payload);
  auto dc = std::get<1>(payload);
  auto options = static_cast<TypeResolutionOptions>(std::get<2>(payload));
  
  // FIXME: TypeChecker::resolveType() is mostly non-ad-hoc-recursive
  // when given an UnsatisfiedDependency.
  TC.resolveType(typeRepr, dc, options, nullptr, &unsatisfiedDependency);
}

bool IterativeTypeChecker::breakCycleForResolveTypeRepr(
       std::tuple<TypeRepr *, DeclContext *, unsigned> payload) {
  std::get<0>(payload)->setInvalid();
  return true;
}

